diff --git a/.gitignore b/.gitignore index 8e6d3e86a..e1dce7f74 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ build/ src/macosx/M6502.ins *.dSYM .vscode/c_cpp_properties.json +.vscode/settings.json src/windows/sdl/* src/windows/x64/* src/windows/Win32/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..164c78f75 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,68 @@ +.core-defs: + variables: + JNI_PATH: src/libretro + CORENAME: stella + +include: + - template: Jobs/Code-Quality.gitlab-ci.yml + - project: 'libretro-infrastructure/ci-templates' + file: '/libnx-static.yml' + - project: 'libretro-infrastructure/ci-templates' + file: '/linux-x64.yml' + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-x64-mingw.yml' + - project: 'libretro-infrastructure/ci-templates' + file: '/android-jni.yml' + +stages: + - build-prepare + - build-shared + - build-static + - test + +#Desktop +libretro-build-linux-x64: + extends: + - .core-defs + - .libretro-linux-x64-make-default + variables: + MAKEFILE_PATH: src/libretro + MAKEFILE: Makefile + +libretro-build-windows-x64: + extends: + - .core-defs + - .libretro-windows-x64-mingw-make-default + variables: + MAKEFILE_PATH: src/libretro + MAKEFILE: Makefile + +# Android +android-armeabi-v7a: + extends: + - .core-defs + - .libretro-android-jni-armeabi-v7a + +android-arm64-v8a: + extends: + - .core-defs + - .libretro-android-jni-arm64-v8a + +android-x86_64: + extends: + - .core-defs + - .libretro-android-jni-x86_64 + +android-x86: + extends: + - .core-defs + - .libretro-android-jni-x86 + +# Static +libretro-build-libnx-aarch64: + extends: + - .core-defs + - .libretro-libnx-static-retroarch-master + variables: + MAKEFILE_PATH: src/libretro + MAKEFILE: Makefile diff --git a/.vscode/settings.json b/.vscode/settings.json index 40ad65881..a55c4e90c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -93,6 +93,11 @@ "vector": "cpp", "memory_resource": "cpp", "cfenv": "cpp", - "cinttypes": "cpp" + "cinttypes": "cpp", + "filesystem": "cpp", + "forward_list": "cpp", + "regex": "cpp", + "valarray": "cpp", + "ranges": "cpp" } } diff --git a/Announce.txt b/Announce.txt index 2262f7975..60eb2f147 100644 --- a/Announce.txt +++ b/Announce.txt @@ -9,7 +9,7 @@ SSSS ttt eeeee llll llll aaaaa =========================================================================== - Release 6.2.1 for Linux, macOS and Windows + Release 6.4 for Linux, macOS and Windows =========================================================================== The Atari 2600 Video Computer System (VCS), introduced in 1977, was the @@ -21,27 +21,25 @@ all of your favourite Atari 2600 games again! Stella was originally developed for Linux by Bradford W. Mott, however, it has been ported to a number of other platforms and is currently maintained by Stephen Anthony. -This is the 6.2.1 release of Stella for Linux, macOS and Windows. The +This is the 6.4 release of Stella for Linux, macOS and Windows. The distributions currently available are: - * Binaries for Windows Vista/7/8/10 : - Stella-6.2.1-win32.exe (32-bit EXE installer) - Stella-6.2.1-x64.exe (64-bit EXE installer) - Stella-6.2.1-windows.zip (32/64 bit versions) + * Binaries for Windows 7/8/10 : + Stella-6.4-win32.exe (32-bit EXE installer) + Stella-6.4-x64.exe (64-bit EXE installer) + Stella-6.4-windows.zip (32/64 bit versions) * Binary distribution for macOS 10.7 and above : - Stella-6.2.1-macos.dmg (64-bit Intel) + Stella-6.4-macos.dmg (64-bit Intel) - * Binary distribution in 32-bit & 64-bit Ubuntu DEB format : - stella_6.2.1-1_i386.deb - stella_6.2.1-1_amd64.deb + * Binary distribution for 64-bit Ubuntu : + stella_6.4-1_amd64.deb - * Binary distribution in 32-bit & 64-bit RPM format : - stella-6.2.1-2.i386.rpm - stella-6.2.1-2.x86_64.rpm + * Binary distribution for 64-bit Redhat : + stella-6.4-2.x86_64.rpm * Source code distribution for all platforms : - stella-6.2.1-src.tar.xz + stella-6.4-src.tar.xz Distribution Site diff --git a/Changes.txt b/Changes.txt index b0691039e..6140d6f59 100644 --- a/Changes.txt +++ b/Changes.txt @@ -12,11 +12,65 @@ Release History =========================================================================== -6.2.1 to 6.3 (XXXX XX, 2020) +6.4 to 6.5 (December XX, 2020) + + * Enhanced cut/copy/paste for text editing. (TODO: PromptWidget) + + * Added undo and redo to text editing. (TODO: PromptWidget) + + * Added wildcard support to launcher dialog filter. + + * Added option to search subdirectories in launcher. + + * Added static tooltips to some UI items. + + * Added dynamic tooltips to most debugger items. + + * Increased sample size for CDFJ+. + + * Fixed autofire bug for trackball controllers. + + * Codebase now uses C++17 features. + +-Have fun! + + +6.3 to 6.4 (November 2, 2020) + + * Added basic (entire and single line only) text cut/copy and paste. + + * Added color parameters to 'Custom' palette. + + * Some improvements to AtariVox-USB adaptor functionality: + - Made serial port used for an AtariVox-USB adaptor editable. + - Autodetection of serial ports no longer messes up devices plugged + into other serial ports. + + * Added CPU load stats to debugger. Related to this, added debugger + pseudo-registers '_ftimreadcycles' and '_fwsynccycles' to show the + number of cycles since the start of frame under certain circumstances + (see manual for more details). + + * Fixed bug with aspect correction and fullscreen mode; snapshots from + such a mode are now pixel-exact. + + * Fixed a bug that caused CDF ROMs to crash on the Retron77 and reduced + ARM emulation performance for CDF ROMs on other platforms. + + * Fixed crash with missing or incorrectly sized SaveKey data file, and + with certain functions not working (erase pages, erase entire EEPROM). + + * Fixed Atari mouse autodetection. + + * Fixed bug in ROM launcher, with last ROM selected not being remembered + when exiting and re-entering a directory. + + +6.2.1 to 6.3 (October 7, 2020) * Added adjustable autofire. - * Added 'Dark' UI theme. (TODO: DOC) + * Added 'Dark' UI theme. * Extended global hotkeys for debug options. @@ -37,19 +91,34 @@ are no longer corrupted/cut off. This includes properly supporting the 2600-daptor II, which is flashable to an AVox-USB converter. + * Added auto-detection of the serial port used for an AtariVox-USB adaptor. + + * Added QuadTari controller support. + * Added option to select the audio device. + * Added support for CDFJ+ bankswitching type. + + * Further enhanced UA bankswitching to support more Brazilian carts. + * Added option to display detected settings info when a ROM is loaded. - * Added another oddball TIA glitch option for delayed background color. (TODO: DOC) + * Added another oddball TIA glitch option for delayed background color. + + * Added option to disable aspect ratio correct scaling. + + * Added debugger pseudo-registers '_timwrapread' and '_timwrapwrite', + which are set when the RIOT timer is read/written on timer wraparound, + respectively. + + * Bankswitching schemes BUS, DPC+ and CDFx now work when startup bank + randomization is enabled (these schemes now ignore that setting). * Replaced "Re-disassemble" with "Disassemble @ current line" in debugger. * Fixed bug when taking fullscreen snapshots; the dimensions were sometimes cut off. --Have fun! - 6.2.1 to 6.2.2 (August 25, 2020) diff --git a/Makefile b/Makefile index 168ae178d..d9dc607c9 100644 --- a/Makefile +++ b/Makefile @@ -48,11 +48,11 @@ endif CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter ifdef HAVE_GCC - CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14 + CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17 endif ifdef HAVE_CLANG - CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14 + CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17 endif ifdef CLANG_WARNINGS @@ -81,8 +81,8 @@ else endif ifdef RELEASE - CXXFLAGS += -flto - LDFLAGS += -flto + CXXFLAGS += -flto -fno-rtti + LDFLAGS += -flto -fno-rtti endif ####################################################################### diff --git a/configure b/configure index 31281ec4c..fbc3c1b39 100755 --- a/configure +++ b/configure @@ -385,7 +385,7 @@ else fi for compiler in $compilers; do - if test_compiler "$compiler -std=c++14"; then + if test_compiler "$compiler -std=c++17"; then CXX=$compiler echo $CXX break @@ -580,6 +580,10 @@ else darwin*) DEFINES="$DEFINES -DUNIX -DDARWIN" _host_os=darwin + if test "$have_clang" = yes; then + CXXFLAGS="$CXXFLAGS -Wno-documentation-unknown-command -Wno-documentation-pedantic -Wno-poison-system-directories" + CXXFLAGS="$CXXFLAGS -Wno-unknown-warning-option" + fi ;; irix*) DEFINES="$DEFINES -DUNIX" @@ -821,8 +825,9 @@ CHEAT="$SRC/cheat" LIBPNG="$SRC/libpng" ZLIB="$SRC/zlib" SQLITE="$SRC/common/repository/sqlite" +JSON="$SRC/json" -INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER" +INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$JSON" INCLUDES="$INCLUDES `$_sdlconfig --cflags`" if test "$_build_static" = yes ; then diff --git a/debian/changelog b/debian/changelog index 75c7267b6..d1456ede4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +stella (6.4) stable; urgency=high + + * Version 6.4 release + + -- Stephen Anthony Mon, 2 Nov 2020 17:09:59 -0230 + + +stella (6.3-1) stable; urgency=high + + * Version 6.3 release + + -- Stephen Anthony Wed, 7 Oct 2020 17:09:59 -0230 + + stella (6.2.1-1) stable; urgency=high * Version 6.2.1 release diff --git a/debian/compat b/debian/compat index ec635144f..f599e28b8 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 +10 diff --git a/debian/control b/debian/control index 4d19b476f..9106212fe 100644 --- a/debian/control +++ b/debian/control @@ -1,17 +1,39 @@ Source: stella -Section: games -Priority: optional Maintainer: Stephen Anthony -Standards-Version: 3.7.2 -Build-Depends: debhelper (>= 5.0.0), libsdl2-dev, libpng-dev +Section: otherosfs +Priority: optional +Build-Depends: debhelper (>= 10~), + libpng-dev, + libsdl2-dev, + zlib1g-dev +Standards-Version: 4.5.0 +Vcs-Browser: https://github.com/stella-emu/stella/ +Vcs-Git: https://github.com/stella-emu/stella.git +Homepage: https://stella-emu.github.io +Rules-Requires-Root: no Package: stella Architecture: any -Depends: ${shlibs:Depends} +Depends: ${misc:Depends}, + ${shlibs:Depends} +Recommends: joystick (>= 1:1.5.1) +Pre-Depends: ${misc:Pre-Depends} Description: Atari 2600 Emulator for SDL2 - The Atari 2600 Video Computer System (VCS), introduced in 1977, was - the most popular home video game system of the early 1980's. This - emulator will run most Atari ROM images, so that you can play your - favorite old Atari 2600 games on your PC. + Stella is a portable emulator of the old Atari 2600 video-game + console. You can play most Atari 2600 games with it. . - Homepage: https://stella-emu.github.io + Stella's features include: + * emulation of Atari 2600 joysticks, keyboards, paddles and driving + controllers using the host system's input peripherals; + * emulation of trackballs, joysticks, booster grips, driving + controllers and the Amiga Mouse using the host system's mouse; + * support for real Atari 2600 controllers using the Stelladaptor, + 2600-daptor or 2600-daptor II; + * support for real Atari 7800 controllers using the 2600-daptor II; + * support for the speech portion of a real AtariVox device; + * support for Supercharger single-load and multi-load games; + * emulation of CRT TV features, including texturing, colour bleed, + RF noise and phosphor burn-off (requires OpenGL). + . + An extensive debugger is included, with the Distella disassembler. + diff --git a/debian/copyright b/debian/copyright index 129ab1224..9658cf4e9 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,29 +1,205 @@ -This package was debianized first by Tom Lear on -Thu, 7 Oct 1999 08:57:16 -0700. +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0 +Upstream-Name: stella +Source: https://stella-emu.github.io +Copyright: 1995-2020 Bradford W. Mott, Stephen Anthony and the Stella Team +License: GPL-2+ -It was downloaded from +Files: * +Copyright: 1995-2020 Bradford W. Mott, Stephen Anthony and the Stella + Team +License: GPL-2+ -Copyright Holder(s): Bradford W. Mott and the Stella Team +Files: debian/* +Copyright: 1998-2004 Tom Lear + 2006 Mario Iseli + 2010-2020 Stephen Kitt +License: GPL-2+ -License: +Files: + src/common/Stack.hxx + src/emucore/FrameBuffer.hxx + src/emucore/FSNode.* + src/gui/* +Copyright: 2002-2004 The ScummVM project +License: GPL-2+ - Copyright (C) 1995-2010 Bradford W. Mott - and the Stella Team +Files: src/common/ZipHandler.hxx +Copyright: Aaron Giles +License: BSD-3 + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name 'MAME' nor the names of its contributors may + be used to endorse or promote products derived from this + software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +Files: src/emucore/MD5.cxx +Copyright: 1991-1992, RSA Data Security, Inc. +License: RSA + License to copy and use this software is granted provided that it is + identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software or + this function. + . + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + . + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" without + express or implied warranty of any kind. + . + These notices must be retained in any copies of any part of this + documentation and/or software. - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +Files: src/libpng/* +Copyright: 1995-1996 Guy Eric Schalnat, Group 42, Inc. + 1996-1997 Andreas Dilger + 1998-2013 Glenn Randers-Pehrson +License: libpng + The PNG Reference Library is supplied "AS IS". The Contributing + Authors and Group 42, Inc. disclaim all warranties, expressed or + implied, including, without limitation, the warranties of + merchantability and of fitness for any purpose. The Contributing + Authors and Group 42, Inc. assume no liability for direct, indirect, + incidental, special, exemplary, or consequential damages, which may + result from the use of the PNG Reference Library, even if advised of + the possibility of such damage. + . + Permission is hereby granted to use, copy, modify, and distribute + this source code, or portions hereof, for any purpose, without fee, + subject to the following restrictions: + . + 1. The origin of this source code must not be misrepresented. + . + 2. Altered versions must be plainly marked as such and must not be + misrepresented as being the original source. + . + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + . + The Contributing Authors and Group 42, Inc. specifically permit, + without fee, and encourage the use of this source code as a component + to supporting the PNG file format in commercial products. If you use + this source code in a product, acknowledgment is not required but + would be appreciated. + . + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is + with the user. - You should have received a copy of the GNU General Public License - along with this package; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +Files: src/libretro/libretro.h +Copyright: 2010-2017 The RetroArch team +License: MIT + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + . + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. -On Debian systems, the complete text of the GNU General -Public License can be found in `/usr/share/common-licenses/GPL'. +Files: src/macos/* +Copyright: 2005-2006 Mark Grebe +License: GPL-2+ +Files: src/tools/convbdf.c +Copyright: 2002 Greg Haerr +License: GPL-2+ + +Files: src/tools/evdev-joystick/* +Copyright: 2016 Stephen Anthony +License: GPL-2 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + . + This package is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA. + . + On Debian systems, the complete text of the GNU General Public + License version 2 can be found in + `/usr/share/common-licenses/GPL-2'. + +Files: src/zlib/* +Copyright: 1995-2012, 2016 Jean-loup Gailly and Mark Adler +License: zlib + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + . + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute + it freely, subject to the following restrictions: + . + 1. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + . + This package is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA. + . + On Debian systems, the complete text of the GNU General Public + License version 2 can be found in + `/usr/share/common-licenses/GPL-2'. diff --git a/debian/dirs b/debian/dirs deleted file mode 100644 index e77248175..000000000 --- a/debian/dirs +++ /dev/null @@ -1 +0,0 @@ -usr/bin diff --git a/debian/doc-base b/debian/doc-base new file mode 100644 index 000000000..dd94cd309 --- /dev/null +++ b/debian/doc-base @@ -0,0 +1,9 @@ +Document: stella +Title: Stella Manual +Author: The Stella Team +Abstract: Documentation for the Stella Atari 2600 VCS emulator. +Section: Emulators + +Format: HTML +Index: /usr/share/doc/stella/index.html +Files: /usr/share/doc/stella/*.html diff --git a/debian/rules b/debian/rules index 2e9b442c1..8277e8a69 100755 --- a/debian/rules +++ b/debian/rules @@ -4,67 +4,26 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -# These are used for cross-compiling and for saving the configure script -# from having to guess our platform (since we know it already) -DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) -DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) -DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) +export DEB_BUILD_MAINT_OPTIONS = hardening=+all -CFLAGS = -Wall +include /usr/share/dpkg/architecture.mk +DPKG_EXPORT_BUILDTOOLS=1 +-include /usr/share/dpkg/buildtools.mk -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CXXFLAGS += -O0 -else - CXXFLAGS += -O2 -endif +%: + dh $@ --with autotools_dev -config.status: configure - dh_testdir - CXXFLAGS="$(CXXFLAGS)" ./configure --prefix=/usr --enable-release +override_dh_auto_clean: +# Generate the minimal config.mak required for "make distclean" + test -f config.mak || echo "RM_REC := rm -f -r" > config.mak + dh_auto_clean -build: build-stamp +override_dh_auto_configure: + ./configure --prefix=/usr $(if $(filter $(DEB_BUILD_ARCH),$(DEB_HOST_ARCH)),,--host=$(DEB_HOST_GNU_TYPE)) --enable-release -build-stamp: config.status - dh_testdir - $(MAKE) - touch build-stamp - -clean: - dh_testdir - dh_testroot - rm -f build-stamp - -$(MAKE) distclean - - dh_clean - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - $(MAKE) install DESTDIR=$(CURDIR)/debian/stella - -# Build architecture-independent files here. -binary-indep: build install -# We have nothing to do by default. - -binary-arch: build install - dh_testdir - dh_testroot - dh_installchangelogs Changes.txt - dh_installdocs - dh_installmenu -# dh_installman $(CURDIR)/debian/stella.6 - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install +override_dh_auto_install: + dh_auto_install + # This is also installed as the upstream changelog + rm $(CURDIR)/debian/stella/usr/share/doc/stella/Changes.txt + # This is overridden by the copyright file + rm $(CURDIR)/debian/stella/usr/share/doc/stella/License.txt diff --git a/debian/watch b/debian/watch index 8cdd8c1ec..b507d13a8 100644 --- a/debian/watch +++ b/debian/watch @@ -1,2 +1,4 @@ -version=3 -http://sf.net/stella/stella-(.*)-src\.tar\.gz +version=4 +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%stella-$1.tar.gz%" \ + https://github.com/stella-emu/stella/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate diff --git a/docs/debugger.html b/docs/debugger.html index 7e51a0333..b1fdac37e 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -15,7 +15,7 @@
Stella
-

Release 6.2.1

+

Release 6.4

Integrated Debugger

(a work in progress)


@@ -227,6 +227,14 @@ tabs from left-to-right, Shift + Control/Cmd + Tab cycles right-to-left. Pressing Tab (or Shift + Tab) cycles between widgets in the current tab (except for in the Prompt Tab, where 'tab' is used for something else).

+

Note for the GUI display: +

    +
  • Hexadecimal values are either not prefixed or with '$'.
  • +
  • Decimal values are prefixed with '#'.
  • +
  • Binary values are prefixed with '%'.
  • +
+

+

You can also enter the debugger at emulator startup by use the 'debug' command on the command line, or alternatively within the ROM launcher in 'Power-on options': @@ -753,10 +761,14 @@ that holds 'number of scanlines' on an actual console).

_cycleslo Lower 32 bits of number of cycles since emulation started _fcount Number of frames since emulation started _fcycles Number of cycles since frame started + _ftimreadcyclesNumber of cycles used by timer reads since frame started + _fwsynccyclesNumber of cycles skipped by WSYNC since frame started _icycles Number of cycles of last instruction _scan Current scanline count _scanend Scanline count at end of last frame _scycles Number of cycles in current scanline + _timwrapread Timer read wrapped on this cycle + _timwrapwrite Timer write wrapped on this cycle _vblank Whether vertical blank is enabled (1 or 0) _vsync Whether vertical sync is enabled (1 or 0) @@ -1131,16 +1143,20 @@ as illustrated:


(F) TIA Information

-

To the right of the TIA Display area, TIA information is displayed:

+

To the right of the TIA Display area, TIA information is displayed (all values are decimal):

The indicators are as follows (note that all these are read-only):

    -
  • Frame Count: The number of frames since this ROM was loaded or reset.
  • -
  • Frame Cycle: The number of CPU cycles that have been executed this frame since +
  • Frame Cycls: The number of CPU cycles that have been executed this frame since +VSYNC was cleared at scanline 0.
  • +
  • WSync Cycls: The number of CPU cycles that have been skipped by WSYNC this frame since +VSYNC was cleared at scanline 0.
  • +
  • Timer Cycls: The number of CPU cycles (approximately) that have been used by timer read loops since VSYNC was cleared at scanline 0.
  • Total: The total number of CPU cycles since this ROM was loaded or reset.
  • Delta: The number of CPU cycles that have been executed since the last debugger interrupt.
  • +
  • Frame Cnt.: The number of frames since this ROM was loaded or reset.
  • Scanline: The scanline that's currently being drawn, and the count from the previous frame. Scanline 0 is the one on which VSYNC is cleared (after being set for 3 scanlines, as per the Stella Programmer's Guide).
  • @@ -1273,10 +1289,9 @@ are lost (they will NOT end up in the Carry flag).

    This is a spreadsheet-like GUI for inspecting and changing the contents of the 2600's zero-page RAM.

    You can navigate with either the mouse or the keyboard arrow keys. -To change a RAM location, either double-click on it or press Enter while -it's highlighted. Enter the new value (hex only for now, sorry), then -press Enter to make the change. If you change your mind, press Escape -and the original value will be restored. The currently selected RAM cell +To change a RAM location, either double-click on it or press 'Enter' while +it's highlighted. Enter the new value (hex, other formats using the bottom textboxes), then +press 'Enter' to make the change. The currently selected RAM cell can also be changed by using the Data Operations Buttons or the associated shortcut keys.

    @@ -1287,7 +1302,8 @@ more comprehensive. It will undo all operations on all cells since you first made a change.

    The UI objects at the bottom refer to the currently selected RAM cell. The 'Label' textbox shows the label attached to this RAM location (if any), -and the other two textboxes show the decimal and binary equivalent value.

    +and the other three textboxes show the hex, decimal and binary equivalent value. +The values can be edited here too.

    The remaining buttons to the right are further explained in the next section.

    @@ -1569,7 +1585,7 @@ Go ahead and try to change something!

    If applicable, this area shows a detailed breakdown of any extra RAM supported by the bankswitching scheme. Since the bankswitch schemes can greatly vary in operation, this tab will be different for each scheme, but its specific functionality should be -self-explanatory. An example of both F8SC (8K Atari + ram) and DPC (Pitfall II) is +self-explanatory. An example of both F6SC (16K Atari + ram) and DPC (Pitfall II) is as follows:

    diff --git a/docs/graphics/debugger_bankcomplex.png b/docs/graphics/debugger_bankcomplex.png index fd8a087dc..ae200386d 100644 Binary files a/docs/graphics/debugger_bankcomplex.png and b/docs/graphics/debugger_bankcomplex.png differ diff --git a/docs/graphics/debugger_banksimple.png b/docs/graphics/debugger_banksimple.png index a5f1092d9..67f16c0cc 100644 Binary files a/docs/graphics/debugger_banksimple.png and b/docs/graphics/debugger_banksimple.png differ diff --git a/docs/graphics/debugger_cpuregs.png b/docs/graphics/debugger_cpuregs.png index feb238c1b..4d868df92 100644 Binary files a/docs/graphics/debugger_cpuregs.png and b/docs/graphics/debugger_cpuregs.png differ diff --git a/docs/graphics/debugger_iotab.png b/docs/graphics/debugger_iotab.png index 170fc47b3..a83fd33ad 100644 Binary files a/docs/graphics/debugger_iotab.png and b/docs/graphics/debugger_iotab.png differ diff --git a/docs/graphics/debugger_main.png b/docs/graphics/debugger_main.png index c59f1a345..2064cd85a 100644 Binary files a/docs/graphics/debugger_main.png and b/docs/graphics/debugger_main.png differ diff --git a/docs/graphics/debugger_ram-dpc.png b/docs/graphics/debugger_ram-dpc.png index 97f682626..3a2e94943 100644 Binary files a/docs/graphics/debugger_ram-dpc.png and b/docs/graphics/debugger_ram-dpc.png differ diff --git a/docs/graphics/debugger_ram-f8sc.png b/docs/graphics/debugger_ram-f8sc.png index dc8b231a8..4ebb9e75a 100644 Binary files a/docs/graphics/debugger_ram-f8sc.png and b/docs/graphics/debugger_ram-f8sc.png differ diff --git a/docs/graphics/debugger_ram.png b/docs/graphics/debugger_ram.png index efdc8531b..a5711bf02 100644 Binary files a/docs/graphics/debugger_ram.png and b/docs/graphics/debugger_ram.png differ diff --git a/docs/graphics/debugger_ramsearch.png b/docs/graphics/debugger_ramsearch.png index 9041ca0a1..a6ed37b8f 100644 Binary files a/docs/graphics/debugger_ramsearch.png and b/docs/graphics/debugger_ramsearch.png differ diff --git a/docs/graphics/debugger_tiainfo.png b/docs/graphics/debugger_tiainfo.png index e19f4ea4a..3ef48b425 100644 Binary files a/docs/graphics/debugger_tiainfo.png and b/docs/graphics/debugger_tiainfo.png differ diff --git a/docs/graphics/eventmapping.png b/docs/graphics/eventmapping.png index f9b089b6d..f1cef67ac 100644 Binary files a/docs/graphics/eventmapping.png and b/docs/graphics/eventmapping.png differ diff --git a/docs/graphics/eventmapping_combo.png b/docs/graphics/eventmapping_combo.png index 18d461971..a8bc4d8cd 100644 Binary files a/docs/graphics/eventmapping_combo.png and b/docs/graphics/eventmapping_combo.png differ diff --git a/docs/graphics/eventmapping_devsports.png b/docs/graphics/eventmapping_devsports.png index 9b3da3ebc..536caf4f4 100644 Binary files a/docs/graphics/eventmapping_devsports.png and b/docs/graphics/eventmapping_devsports.png differ diff --git a/docs/graphics/eventmapping_mouse.png b/docs/graphics/eventmapping_mouse.png index daac75b09..760b4eac3 100644 Binary files a/docs/graphics/eventmapping_mouse.png and b/docs/graphics/eventmapping_mouse.png differ diff --git a/docs/graphics/eventmapping_remap.png b/docs/graphics/eventmapping_remap.png index 34df62937..442dfead6 100644 Binary files a/docs/graphics/eventmapping_remap.png and b/docs/graphics/eventmapping_remap.png differ diff --git a/docs/graphics/launcher_override.png b/docs/graphics/launcher_override.png index 17302c994..a4b3b4221 100644 Binary files a/docs/graphics/launcher_override.png and b/docs/graphics/launcher_override.png differ diff --git a/docs/graphics/logs.png b/docs/graphics/logs.png index 202272ad5..195eeed28 100644 Binary files a/docs/graphics/logs.png and b/docs/graphics/logs.png differ diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png index e46d77b87..174bc3701 100644 Binary files a/docs/graphics/options_audio.png and b/docs/graphics/options_audio.png differ diff --git a/docs/graphics/options_developer.png b/docs/graphics/options_developer.png index f405818b1..f39e894b8 100644 Binary files a/docs/graphics/options_developer.png and b/docs/graphics/options_developer.png differ diff --git a/docs/graphics/options_developer_debugger.png b/docs/graphics/options_developer_debugger.png index dfa8cbd73..4ad4d42d7 100644 Binary files a/docs/graphics/options_developer_debugger.png and b/docs/graphics/options_developer_debugger.png differ diff --git a/docs/graphics/options_developer_emulation.png b/docs/graphics/options_developer_emulation.png index 977893402..0b2f32d65 100644 Binary files a/docs/graphics/options_developer_emulation.png and b/docs/graphics/options_developer_emulation.png differ diff --git a/docs/graphics/options_developer_tia.png b/docs/graphics/options_developer_tia.png index ee3a3973c..dbacdc877 100644 Binary files a/docs/graphics/options_developer_tia.png and b/docs/graphics/options_developer_tia.png differ diff --git a/docs/graphics/options_developer_timemachine.png b/docs/graphics/options_developer_timemachine.png index 498f83c0f..d912666bc 100644 Binary files a/docs/graphics/options_developer_timemachine.png and b/docs/graphics/options_developer_timemachine.png differ diff --git a/docs/graphics/options_developer_video.png b/docs/graphics/options_developer_video.png index 0bc3393f4..42b55dff8 100644 Binary files a/docs/graphics/options_developer_video.png and b/docs/graphics/options_developer_video.png differ diff --git a/docs/graphics/options_gameinfo_controller.png b/docs/graphics/options_gameinfo_controller.png index fe5adb275..2714e5407 100644 Binary files a/docs/graphics/options_gameinfo_controller.png and b/docs/graphics/options_gameinfo_controller.png differ diff --git a/docs/graphics/options_gameinfo_emulation.png b/docs/graphics/options_gameinfo_emulation.png index 221a08fa5..55c1e6893 100644 Binary files a/docs/graphics/options_gameinfo_emulation.png and b/docs/graphics/options_gameinfo_emulation.png differ diff --git a/docs/graphics/options_gameinfo_quadtari.png b/docs/graphics/options_gameinfo_quadtari.png new file mode 100644 index 000000000..04fba7f06 Binary files /dev/null and b/docs/graphics/options_gameinfo_quadtari.png differ diff --git a/docs/graphics/options_misc.png b/docs/graphics/options_misc.png index 1faa756b5..704b7b5de 100644 Binary files a/docs/graphics/options_misc.png and b/docs/graphics/options_misc.png differ diff --git a/docs/graphics/options_misc_dark.png b/docs/graphics/options_misc_dark.png new file mode 100644 index 000000000..79fad1166 Binary files /dev/null and b/docs/graphics/options_misc_dark.png differ diff --git a/docs/graphics/options_ui.png b/docs/graphics/options_ui.png index 54ed568fc..70712d2b6 100644 Binary files a/docs/graphics/options_ui.png and b/docs/graphics/options_ui.png differ diff --git a/docs/graphics/options_video.png b/docs/graphics/options_video.png index 58654148a..193bc4804 100644 Binary files a/docs/graphics/options_video.png and b/docs/graphics/options_video.png differ diff --git a/docs/graphics/options_video_palettes.png b/docs/graphics/options_video_palettes.png index dae0cf7ee..d965b45b3 100644 Binary files a/docs/graphics/options_video_palettes.png and b/docs/graphics/options_video_palettes.png differ diff --git a/docs/graphics/options_video_tv.png b/docs/graphics/options_video_tv.png index 5ce3c3f2a..01b460842 100644 Binary files a/docs/graphics/options_video_tv.png and b/docs/graphics/options_video_tv.png differ diff --git a/docs/graphics/resources/debugger_main.pdn b/docs/graphics/resources/debugger_main.pdn index 6c864a2a4..16d370b08 100644 Binary files a/docs/graphics/resources/debugger_main.pdn and b/docs/graphics/resources/debugger_main.pdn differ diff --git a/docs/graphics/rominfo_1x_large.png b/docs/graphics/rominfo_1x_large.png index e5b08d857..5a0133404 100644 Binary files a/docs/graphics/rominfo_1x_large.png and b/docs/graphics/rominfo_1x_large.png differ diff --git a/docs/graphics/rominfo_1x_small.png b/docs/graphics/rominfo_1x_small.png index 6ee356745..99d23e135 100644 Binary files a/docs/graphics/rominfo_1x_small.png and b/docs/graphics/rominfo_1x_small.png differ diff --git a/docs/graphics/rominfo_2x_small.png b/docs/graphics/rominfo_2x_small.png index da610bba0..7c53384b2 100644 Binary files a/docs/graphics/rominfo_2x_small.png and b/docs/graphics/rominfo_2x_small.png differ diff --git a/docs/index.html b/docs/index.html index 89bee1158..369598e23 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,7 +19,7 @@

    A multi-platform Atari 2600 VCS emulator

    -

    Release 6.2.1

    +

    Release 6.4



    User's Guide

    @@ -70,7 +70,7 @@


    -
    February 1999 - June 2020
    +
    February 1999 - November 2020
    The Stella Team
    Stella Homepage
    @@ -260,7 +260,7 @@

    Features

      -
    • High speed emulation using optimized C++14 code
    • +
    • High speed emulation using optimized C++17 code
    • Supports high quality TIA emulation using the cycle-exact TIA core from 6502.ts by Christian Speckner
    • @@ -268,24 +268,15 @@ Atari 2600 FPGA project, including cycle-exact audio, analog interference from mixing of audio channels, as well as stereo sound support; dynamic sound resampling is also included -
    • Emulates the Atari 2600 Joystick Controllers using your computer's keyboard, +
    • Emulates the Atari 2600 Joystick, Paddle, Driving, CBS BoosterGrip, Sega Genesis, QuadTari controllers using your computer's keyboard, joysticks or mouse
    • -
    • Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard
    • -
    • Emulates the Atari 2600 Paddle Controllers using your computer's mouse, keyboard - or joysticks
    • -
    • Emulates the Atari 2600 Driving Controllers using your computer's keyboard, - joysticks or mouse
    • -
    • Emulates the CBS BoosterGrip Controller using your computer's keyboard, - joysticks or mouse
    • -
    • Emulates the Sega Genesis Controller using your computer's keyboard, - joysticks or mouse
    • -
    • Emulates CX22/CX80 style trackballs and Amiga/Atari Mouse using your +
    • Emulates CX22/CX80 style Trackballs, Amiga/Atari Mouse, Mindlink controller and the Light Gun using your computer's mouse
    • +
    • Emulates the Atari 2600 Keyboard controllers using your computer's keyboard
    • Emulates Spectravideo CompuMate system using your computer's keyboard, including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to to the actual keys on your keyboard
    • -
    • Emulates the Mindlink Controller and the Light Gun using your computer's mouse
    • -
    • Supports autodetection for most common controller types
    • +
    • Supports autodetection for most common controller types
    • Support for real Atari 2600 controllers using the Stelladaptor and 2600-daptor/2600-daptor II
    • @@ -296,7 +287,7 @@ AtariVox and SaveKey controllers, as well as FLASH support in various cartridge schemes
    • Supports all known bankswitching schemes (let us know if there's one we missed)
    • -
    • Supports DPC+/CDF(J) bankswitching schemes from the Harmony Cart, +
    • Supports DPC+/CDF(J)(+) bankswitching schemes from the Harmony Cart, including partial emulation of the ARM processor
    • Supports cartridge autodetection for almost all bankswitching schemes
    • Supports using ROM filename extensions to force specific bankswitching schemes
    • @@ -359,7 +350,7 @@
    • OpenGL capable video card
    • Other architectures (MIPS, PPC, PPC64, etc.) have been confirmed to work, but aren't as well tested as i386/x86_64
    • -
    • GNU g++ v/6 or Clang v/3.9 (with C++14 support) and the make utility are required for compiling the Stella source code
    • +
    • GNU g++ v/7 or Clang v/5 (with C++17 support) and the make utility are required for compiling the Stella source code

    @@ -377,7 +368,7 @@

    Windows

    -

    The Windows version of Stella is designed to work on Windows Vista/7/8/10 +

    The Windows version of Stella is designed to work on Windows 7/8/10 with the following:

      @@ -1373,8 +1364,8 @@ Toggle windowed/fullscreen mode - Alt + Enter - Cmd + Enter + Alt + Return + Cmd + Return Toggle adapting display refresh rate to game frame rate @@ -1403,6 +1394,11 @@ Alt + PageUp Cmd-Fn + Up arrow + + Toggle aspect ratio correct scaling + Control + c + Control + c + Decrease vertical display size Shift-Alt + PageUp @@ -1761,11 +1757,6 @@ Backspace Backspace - - Go to parent directory (UI mode) - Backspace - Backspace - Decrease emulation speed (disables 'Turbo' mode) Shift-Control + s @@ -1793,7 +1784,7 @@ - Switch mouse between controller emulation modes
      (see Game Properties - Controller) + Switch mouse between controller emulation modes
      (see Controller Properties) Control + 0 Control + 0 @@ -1810,13 +1801,13 @@ Save continuous PNG snapshots
      (per interval defined in Snapshot Settings) - Alt + s - Cmd + s + Control-Alt + s + Control-Cmd + s Save continuous PNG snapshots (every frame) - Shift-Alt + s - Shift-Cmd + s + Shift-Control-Alt + s + Shift-Control-Cmd + s @@ -1871,25 +1862,237 @@ +

      UI Keys (can be remapped)

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      FunctionKey (Standard)Key (macOS)
      Move UpUp arrowUp arrow
      Move DownDown arrowDown arrow
      Move LeftLeft arrowLeft arrow
      Move RightRight arrowRight arrow
      Move HomeHomeHome
      Move EndEndEnd
      Move Page UpPage UpPage Up
      Move Page DownPage DownPage Down
      OK--
      CancelEscapeEscape
      Select itemReturn/Enter/SpaceReturn/Enter/Space
      Move to previous objectShift + TabShift + Tab
      Move to next objectTabTab
      Move to previous tabShift-Control + TabShift-Control + Tab
      Move to next tabControl + TabControl + Tab
      Go to parent directoryBackspaceBackspace
      Toggle windowed/fullscreen modeAlt + ReturnCmd + Return
      Exit emulatorControl + qCmd + q
      +

      UI Keys in Text Editing areas (cannot be remapped)

      - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      KeyEditor Function
      HomeMove cursor to beginning of line
      EndMove cursor to end of line
      DeleteRemove character to right of cursor
      BackspaceRemove character to left of cursor
      Control-aSame function as 'Home'
      Control-eSame function as 'End'
      Control-dSame function as 'Delete'
      Control-kRemove all characters from cursor to end of line
      Control-uRemove all characters from cursor to beginning of line
      Control-wRemove entire word to left of cursor
      Control-LeftMove cursor to beginning of word to the left
      Control-RightMove cursor to beginning of word to the right
      Control-cCopy entire line to clipboard (not complete)
      Control-vPaste clipboard contents (not complete)
      FunctionKey (Standard)Key (macOS)
      Move cursor to previous characterLeft arrowLeft arrow
      Move cursor to next characterRight arrowRight arrow
      Move cursor to beginning of current wordControl + Left arrowOption + Left arrow
      Move cursor to beginning of next wordControl + Right arrowOption + Right arrow
      Move cursor to beginning of lineHomeHome, Control + a, Command + Left arrow
      Move cursor to end of lineEndEnd, Control + e, Command + Right arrow
      Delete character to left of cursorBackspaceBackspace
      Delete character to right of cursorDelete, Control + dDelete, Control + d
      Delete word to left of cursorControl + Backspace, Control + wOption + Backspace, Control + w
      Delete word to right of cursorControl + Delete, Alt + dOption + Delete
      Delete all text to beginning of lineControl + Home, Control + uCommand + Backspace, Control + u
      Delete all text to end of lineControl + End, Control + kControl + k
      Select character to left of cursorShift + Left arrowShift + Left arrow
      Select character to right of cursorShift + Right arrowShift + Right arrow
      Select all text to beginning of current wordShift-Control + Left arrowShift-Option + Left arrow
      Select all text to beginning of next wordShift-Control + Right arrowShift-Option + Right arrow
      Select all text to beginning of lineShift + HomeShift + Home, Shift-Control + a, Shift-Command + Left arrow
      Select all text to end of lineShift + EndShift + End, Shift-Control + e, Shift-Command + Right arrow
      Select all textControl + aCommand + a
      Cut selected textControl + x, Shift + DeleteCommand + x
      Copy selected textControl + c, Control + InsertCommand + c
      Paste at cursor and replace selectionControl + v, Shift + InsertCommand + v
      Undo last operationControl + zCommand + z
      Redo last operationControl + y, Shift-Control + zCommand + y, Shift-Command + z
      +
      +

      Controller Map

      @@ -2085,9 +2288,9 @@

      In addition to the built in ROM launcher, Stella can also be used from the - commandline (assuming your operating system has a commandline).

      + command line (assuming your operating system has a command line).

      -

      To run Stella from the commandline, use the following format:

      +

      To run Stella from the command line, use the following format:

         stella [options ...] ROM_FILENAME
      @@ -2119,24 +2322,24 @@
      -center <1|0>
      - Centers all windows (if possible). + Center all windows (if possible).
      -windowedpos <XxY>
      - Sets the window position in windowed emulator mode. + Set the window position in windowed emulator mode.
      -display <number>
      - Sets the display for Stella's emulator. + Set the display for Stella's emulator.
      -palette <standard|z26|user|custom>
      Set the palette to either normal Stella, the one used in the z26 emulator, a user-defined palette, or a custom palette generated - from user-defined phase shifts. + from user-defined parameters. @@ -2149,6 +2352,36 @@ Adjust phase shift of 'custom' PAL palette. + +
      -pal.red_scale <number>
      + Adjust red scale of 'custom' palette (range -1.0 to 1.0). + + + +
      -pal.red_shift <number>
      + Adjust red shift of 'custom' palette (range -22.5 to 22.5). + + + +
      -pal.green_scale <number>
      + Adjust green scale of 'custom' palette (range -1.0 to 1.0). + + + +
      -pal.green_shift <number>
      + Adjust green shift of 'custom' palette (range -22.5 to 22.5). + + + +
      -pal.blue_scale <number>
      + Adjust blue scale of 'custom' palette (range -1.0 to 1.0). + + + +
      -pal.blue_shift <number>
      + Adjust blue shift of 'custom' palette (range -22.5 to 22.5). + +
      -pal.hue <number>
      Adjust hue of current palette (range -1.0 to 1.0). @@ -2191,108 +2424,113 @@ shown. - -
      -audio.enabled <1|0>
      - Enable or disable sound generation. - + +
      -audio.enabled <1|0>
      + Enable or disable sound generation. + - -
      -audio.volume <0 - 100>
      - Set the volume. - + +
      -audio.volume <0 - 100>
      + Set the volume. + - -
      -audio.device <number>
      - Set the audio device (0 = default). - + +
      -audio.device <number>
      + Set the audio device (0 = default). + - -
      -audio.preset <1 - 5>
      - Set an audio preset. Numbers in sequence represent presets for - 'custom', 'low quality, medium lag', 'high quality, medium lag', - 'high quality, low lag' and 'ultra quality, minimal lag'. - + +
      -audio.preset <1 - 5>
      + Set an audio preset. Numbers in sequence represent presets for + 'custom', 'low quality, medium lag', 'high quality, medium lag', + 'high quality, low lag' and 'ultra quality, minimal lag'. + - -
      -audio.fragment_size <128|256|512|1024|2048|4096>
      - Set the number of samples in a single fragment processed by the audio driver. - + +
      -audio.fragment_size <128|256|512|1024|2048|4096>
      + Set the number of samples in a single fragment processed by the audio driver. + - -
      -audio.sample_rate <44100|48000|96000>
      - Set sound sample output frequency. - + +
      -audio.sample_rate <44100|48000|96000>
      + Set sound sample output frequency. + - -
      -audio.resampling_quality <1|2|3>
      - Set resampling quality to low (1), high (2) or ultra (3). - + +
      -audio.resampling_quality <1|2|3>
      + Set resampling quality to low (1), high (2) or ultra (3). + - -
      -audio.headroom <0 - 20>
      - Set number of additional half-frames to prebuffer. - + +
      -audio.headroom <0 - 20>
      + Set number of additional half-frames to prebuffer. + - -
      -audio.buffer_size <0 - 20>
      - Set maximum number of additional half-frames to buffer. - + +
      -audio.buffer_size <0 - 20>
      + Set maximum number of additional half-frames to buffer. + - -
      -audio.stereo <1|0>
      - Enable or disable stereo mode for all ROMs. - + +
      -audio.stereo <1|0>
      + Enable or disable stereo mode for all ROMs. + - -
      -audio.dpc_pitch <10000 - 30000>
      - Set the pitch of Pitfall II music. - + +
      -audio.dpc_pitch <10000 - 30000>
      + Set the pitch of Pitfall II music. + - -
      -tia.zoom <zoom>
      - Use the specified zoom level (integer) while in TIA/emulation mode. - - + +
      -tia.zoom <zoom>
      + Use the specified zoom level (integer) while in TIA/emulation mode. + + - -
      -tia.vsizeadjust <-5 - 5>
      - Adjust the display height of the TIA image - - + +
      -tia.vsizeadjust <-5 - 5>
      + Adjust the display height of the TIA image + + - -
      -tia.inter <1|0>
      - Use interpolation for the TIA image (results in blending/smoothing - of the image). - + +
      -tia.inter <1|0>
      + Use interpolation for the TIA image (results in blending/smoothing + of the image). + - -
      -tia.fs_stretch <1|0>
      - Stretch TIA image completely while in fullscreen mode, vs. keeping the correct - aspect ratio. - + +
      -tia.fs_stretch <1|0>
      + Stretch TIA image completely while in fullscreen mode, vs. keeping the correct + aspect ratio. + - -
      -tia.fs_refresh <1|0>
      - While in fullscreen mode, adapt the display's refresh rate to the game's frame rate - to minimize judder.
      - Note: Not available for macOS. - + +
      -tia.fs_refresh <1|0>
      + While in fullscreen mode, adapt the display's refresh rate to the game's frame rate + to minimize judder.
      + Note: Not available for macOS. + - -
      -tia.fs_overscan <0 - 10>
      - Add overscan to TIA image while in fullscreen mode + +
      -tia.fs_overscan <0 - 10>
      + Add overscan to TIA image while in fullscreen mode
      -tia.dbgcolors <roygbp>
      - Assigns the colours (R)ed, (O)range, (Y)ellow, (G)reen, (B)lue and (P)urple + Assign the colours (R)ed, (O)range, (Y)ellow, (G)reen, (B)lue and (P)urple to each graphical register P0/M0/P1/M1/PF/BL, respectively. Currently, these change be changed around to apply different colours to the respective register. + +
      -tia.correct_aspect <1|0>
      + Enable aspect ratio correct scaling. + +
      -tv.filter <0 - 5>
      Blargg TV effects, 0 is disabled, next numbers in @@ -2332,7 +2570,7 @@
      -tv.phosphor <always|byrom>
      - Determines how phosphor mode is enabled. If 'always', then the + Determine how phosphor mode is enabled. If 'always', then the ROM properties entry is ignored, and phosphor mode is always turned on. Otherwise, the ROM properties determine whether phosphor mode is used for each ROM. @@ -2354,7 +2592,7 @@
      -tv.scanlines <0 - 100>
      - TV effects scanline intensity, where 0 means completely off. Note: No scanlines in 1x mode snapshots. + Set TV effects scanline intensity, where 0 means completely off. Note: No scanlines in 1x mode snapshots. @@ -2364,17 +2602,17 @@
      -loglevel <0|1|2>
      - Indicates level of logging to perform while the application is running. Zero completely disables logging (except for serious errors), while the remaining numbers show increasingly more detail. + Indicate level of logging to perform while the application is running. Zero completely disables logging (except for serious errors), while the remaining numbers show increasingly more detail.
      -logtoconsole <1|0>
      - Indicates that logged output should be printed to the console/commandline as it's being collected. An internal log will still be kept, and the amount of logging is still controlled by 'loglevel'. + Indicate that logged output should be printed to the console/command line as it's being collected. An internal log will still be kept, and the amount of logging is still controlled by 'loglevel'.
      -joydeadzone <number>
      - Sets the joystick axis deadzone area for analog joysticks/gamepads. + Set the joystick axis deadzone area for analog joysticks/gamepads. All values within the deadzone are treated as zero-axis values, while only those values outside are registered as valid input. Accepts a number from 0 - 29, and uses the formula @@ -2419,17 +2657,17 @@
      -modcombo <1|0>
      - Use modifier(Shift/Alt/Control)-x key combos. This is normally enabled, - since the 'Quit' command is tied to 'Control-q'. However, there are times + Use modifier(Shift/Alt/Control) + x key combos. This is normally enabled, + since the 'Quit' command is tied to 'Control + q'. However, there are times when you want to disable them.
      E.g. a 2-player game is using either the 'f' or 'r' keys for movement, and pressing Control (for Fire) will perform an unwanted action - associated with Control-r or Control-f default keys. + associated with 'Control + r' or 'Control + f' default keys.
      -saport <lr|rl>
      - Determines how to enumerate the Stelladaptor/2600-daptor devices in the + Determine how to enumerate the Stelladaptor/2600-daptor devices in the order they are found: 'lr' means first is left port, second is right port, 'rl' means the opposite. @@ -2475,7 +2713,7 @@
      -grabmouse <1|0>
      - Locks the mouse cursor in the game window in emulation mode. + Lock the mouse cursor in the game window in emulation mode. @@ -2541,7 +2779,7 @@
      -listrominfo
      - Prints relevant contents of the Stella ROM database, one ROM per line, + Print relevant contents of the Stella ROM database, one ROM per line, and then exit Stella. This can be used for external frontends. @@ -2553,12 +2791,12 @@
      -launcherpos <XxY>
      - Sets the window position in windowed ROM launcher mode. + Set the window position in windowed ROM launcher mode.
      -launcherdisplay <number>
      - Sets the display for the ROM launcher. + Set the display for the ROM launcher. @@ -2585,7 +2823,7 @@ -
      -uipalette <standard|classic|light>
      +
      -uipalette <standard|classic|light|dark>
      Use the specified palette for UI elements. @@ -2601,7 +2839,7 @@
      -hidpi <0|1>
      - Enables the HiDPI mode which scales the UI by a factor of two. + Enable the HiDPI mode which scales the UI by a factor of two. @@ -2688,13 +2926,13 @@
      -dis.gfxformat <2|16>
      - Sets the base to use for displaying GFX sections in the disassembler. + Set the base to use for displaying GFX sections in the disassembler.
      -dis.showaddr <1|0>
      - Shows/hides opcode addresses in the disassembler. + Show/hide opcode addresses in the disassembler. @@ -2704,12 +2942,12 @@
      -dbg.pos <XxY>
      - Sets the window position in windowed debugger mode. + Set the window position in windowed debugger mode.
      -dbg.display <number>
      - Sets the display for the debugger. + Set the display for the debugger. @@ -2778,7 +3016,7 @@
      -bs <type>
      - Set "Cart.Type" property. See the Game Properties section + Set "Cart.Type" property. See the Emulation Properties section for valid types. @@ -2819,20 +3057,51 @@
      -lc <type>
      - Set "Controller.Left" property. See the Game Properties + Set "Controller.Left" property. See the Controller Properties + section for valid types. + + + +
      -lq1 <type>
      + Set "Controller.Left1" property for QuadTari. See the QuadTari Properties + section for valid types. + + + +
      -lq2 <type>
      + Set "Controller.Left2" property for QuadTari. See the QuadTari Properties section for valid types.
      -rc <type>
      - Set "Controller.Right" property. See the Game Properties + Set "Controller.Right" property. See the Controller Properties + section for valid types. + + + + +
      -rq1 <type>
      + Set "Controller.Right1" property for QuadTari. See the QuadTari Properties + section for valid types. + + + +
      -rq2 <type>
      + Set "Controller.Right2" property for QuadTari. See the QuadTari Properties section for valid types.
      -bc <type>
      - Sets both "Controller.Left" and "Controller.Right" properties. - See the Game Properties section for valid types. + Set both "Controller.Left" and "Controller.Right" properties. + See the Controller Properties section for valid types. + + + +
      -aq <type>
      + Set "Controller.Left1", "Controller.Left2", "Controller.Right1" and "Controller.Right2" properties for QuadTari. + See the QuadTari Properties section for valid types. @@ -2853,12 +3122,12 @@
      -ma <Auto|XY>
      Set "Controller.MouseAxis" property. - See the Game Properties section for valid types. + See the Controller Properties section for valid types.
      -format <format>
      - Set "Display.Format" property. See the Game Properties section + Set "Display.Format" property. See the Emulation Properties section for valid formats. @@ -2940,7 +3209,7 @@ When enabled, each read or write access to the AtariVox/SaveKey EEPROM is signalled by a message. -
      -dev.tia.type <standard|koolaidman|
      cosmicark|pesco|quickstep|heman|custom>
      +
      -dev.tia.type <standard|koolaidman|cosmicark|
      pesco|quickstep|indy500|heman|custom>
      Set emulated TIA type.
      -dev.tia.plinvphase <1|0>
      @@ -2957,6 +3226,9 @@
      -dev.tia.delaypfcolor <1|0>
      Enable/disable playfield color delayed by one color clock (colored step borders in Quick Step!). + +
      -dev.tia.delaybkcolor <1|0>
      + Enable/disable background color delayed by one color clock (stray pixels in Indy 500 menu hack).
      -dev.tia.delayplswap <1|0>
      Enable/disable player swap delayed by one color clock (He-Man title glitch). @@ -3017,17 +3289,19 @@      - - - - + + + + - - + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      RendererUse specified rendering mode-video
      InterpolationEnable interpolation of the TIA image-tia.inter
      ZoomZoom level of the TIA image-tia.zoom
      ItemBrief descriptionFor more information,
      see Command Line
      RendererUse specified rendering mode.-video
      InterpolationEnable interpolation of the TIA image.-tia.inter
      ZoomAdjust the zoom level of the TIA image-tia.zoom
      FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen
      StretchIn fullscreen mode, completely fill screen with the TIA image.-tia.fs_stretch
      Adapt display...In fullscreen mode, adapt the display's refresh rate to the game's frame rate to minimize judder.
      Note: Not available for macOS.
      -tia.fs_refresh
      OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan
      V-Size adjustAdjust height of the TIA image-tia.vsizeadjust
      OverscanIn fullscreen mode, add overscan to the TIA image.-tia.fs_overscan
      Correct aspect ratioEnable aspect ratio correct scaling. +
      Note: Creates a cleaner looking TIA image when disabled (like z26 and old versions of Stella) vs. a correctly emulated aspect ratio when enabled.
      -tia.correct_aspect
      V-Size adjustAdjust the height of the TIA image.-tia.vsizeadjust
      @@ -3041,10 +3315,13 @@      - + - - + + + + + @@ -3063,7 +3340,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      PalettePalette used for emulation mode-palette
      NTSC phaseAdjust phase shift for 'Custom' NTSC palette-pal.phase_ntsc
      PAL phaseAdjust phase shift for 'Custom' PAL palette-pal.phase_pal
      NTSC phaseAdjust phase shift of 'Custom' NTSC palette-pal.phase_ntsc
      PAL phaseAdjust phase shift of 'Custom' PAL palette-pal.phase_pal
      RAdjust red scale and shift of 'Custom' palette-pal.red_scale, -pal.red_shift
      GAdjust green scale and shift of 'Custom' palette-pal.green_scale, -pal.green_shift
      BAdjust blue scale and shift of 'Custom' palette-pal.blue_scale, -pal.blue_shift
      HueAdjust hue of currently selected palette-pal.hue
      SaturationAdjust saturation of currently selected palette-pal.saturation
      ContrastAdjust contrast of currently selected palette-pal.contrast
           - + @@ -3089,7 +3366,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      TV modeDisable TV effects, or select TV preset-tv.filter
      Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.sharpness, -tv.resolution, etc.
      Phosphor for all ROMsEnable phosphor mode for all ROMs-tv.phosphor
           - + @@ -3134,7 +3411,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Enable audioSelf-explanatory-audio.enabled
      VolumeSelf-explanatory-audio.volume
      DeviceUse the specified audio device.-audio.device
           - + @@ -3181,7 +3458,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Emulation speedEmulation speed-speed
      VSyncEnable vertical synced updates-vsync
      TurboEnable 'Turbo' mode for maximum emulation speed. This overwrites 'Emulation speed' setting and disables 'VSync'.-turbo
           - + @@ -3200,6 +3477,9 @@ + + +
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      ThemeTheme to use for UI elements (see examples)-uipalette
      Dialogs fontThe font used in the dialogs-dialogfont
      HiDPI modeScale the UI by a factor of two when enabled-hidpi
          

      @@ -3219,7 +3499,7 @@
           - + @@ -3332,7 +3612,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Save pathSpecifies where to save snapshots-snapsavedir
      Continuous snapshot intervalInterval (in seconds) between snapshots-ssinterval
           - + @@ -3357,7 +3637,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Joystick deadzone sizeDeadzone area for axes on joysticks/gamepads-joydeadzone
      (Analog paddle) SensitivitySensitivity of an analog paddle-psense
      Analog paddle) Dejitter averagingStrength of paddle input averaging, suppresses mouse jitter-dejitter.base
           - + @@ -3409,15 +3689,29 @@

      ROM Info Viewer width at 50% , UI sized 1280x900, large launcher font:

      -

      The text box in the upper right corner can be used to narrow down the - results in the ROM listing. When this box is empty, all files are shown - (subject to the restrictions from the filtering option, explained below). - Typing characters here will show only those files that match that - pattern. For example, typing 'Activision' will show only files that - contain the word 'Activision' in their name. This is very useful for - quickly finding a group of related ROMs. Note that the search is not - case sensitive, so you don't need to worry about capital or lower-case - letters.

      +

      The dialog items at the top can be used to define the listed files:

      + +
        +
      • + The 'Show all files' checkbox allows displaying files which do not + have a valid ROM extension. +
      • + If 'Incl. subdirectories' is checked, Stella will list matching files + from all subdirectories too. +
      • + The 'Filter' text box can be used to narrow down the results in the + ROM listing. When this box is empty, all files are shown. Typing + characters here will show only those files that match that + pattern. For example, typing 'Activision' will show only files that + contain the word 'Activision' in their name. This is very useful for + quickly finding a group of related ROMs.
        + Note that the search is not case sensitive, so you don't need to worry + about capital or lower-case letters. You also can use '*' and '?' as + wildcards. E.g. for '(198?)*atari' only ROMs from the 1980s made by + Atari will be listed. +
      • +
      +

      ROM Launcher Context Menu

      @@ -3455,14 +3749,8 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Use mouse as ...Allow the mouse to emulate various controllers-usemouse
      (Sensitivity) PaddleSensitivity used when emulating a paddle using a mouse-msense
      (Sensitivity) TrackballSensitivity used when emulating a trackball device using a mouse-tsense
      -
    • Show only ROM files: Selecting this reloads the current listing, - showing only files that have a valid ROM extension.
    • - -
    • Show all files: Selecting this reloads the current listing, - showing all files (with no restriction on file name).
    • -
    • Reload listing: Selecting this performs a reload of the - current listing. It is an alternative to pressing the Control-r + current listing. It is an alternative to pressing the 'Control + r' key combo.

    • @@ -3529,7 +3817,7 @@
    • Any other devices will be ignored.
    • The assignment ordering of Stelladaptor/2600-daptor to port can be redefined with - 'saport' (see description in Using the Command Line) and dynamically with the 'Control-1' key + 'saport' (see description in Using the Command Line) and dynamically with the 'Control + 1' key combo.

    • @@ -3544,7 +3832,7 @@ which allow your particular operating system to 'see' the device (configuring this is outside the scope of this document). Once your operating system properly detects the AtariVox, you will need to tell Stella which serial - port it is connected to. This is done by using the '-avoxport' commandline + port it is connected to. This is done by using the '-avoxport' command line argument, or by setting it in the UI under the 'Devices & Ports' tab in Advanced Configuration - Input Devices.

      @@ -3606,7 +3894,7 @@
           - + @@ -3621,7 +3909,7 @@ - + @@ -3643,17 +3931,20 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Player/Developer settingsSelects the active settings set-dev.settings
      Console info overlayOverlay console info on the TIA image during emulation.-plr.stats
      -dev.stats
      Detected settings infoDisplay detected settings when a ROM is loaded.-plr.detectedinfo
      -dev.detectedinfo
      -dev.rwportbreak
      Break on write to ...Break on writes to ... A write to a read port interrupts emulation and the debugger is entered. -dev.wrportbreak
           - + - + pixel) and Quick Step! (colored step borders). + + @@ -3670,7 +3961,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Chip typeType of emulated TIA chip. Allows testing for TIA versions which exhibit timing problems in certain games. The 'Custom' option allows testing for glitch combinations.-dev.tia.type
      Inverted HMOVE clock...Emulates the Kool-Aid Man collision and Cosmic Ark stars glitches for the given objects. -dev.tia.plinvphase
      -dev.tia.msinvphase
      -dev.tia.blinvphase
      Delayed PlayfieldEmulates playfield registers delayed +
      Delayed PlayfieldEmulates playfield register changes delayed by one color clock. This e.g. causes glitches in Pesco (stray playfield - pixel) and Quick Step! (colored step borders) -dev.tia.delaypfbits
      -dev.tia.delaypfcolor
      Delayed BackgroundEmulates background color register changes delayed + by one color clock. This causes stray pixel in the Indy 500 menu hack.-dev.tia.delaybkcolor
      Delayed VDEL... swap forEmulates a VDELP0/P1/BL swap delayed by one color clock. This e.g cause glitches in the He-Man title screen.     - + @@ -3698,7 +3989,7 @@
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Jitter/roll effectEmulate screen roll with inconsistent scanline count-plr.tv.jitter
      -dev.tv.jitter
      (Jitter/roll) RecoveryDetermines recovery time for screen rolling-plr.tv.jitter_recovery
      -dev.tv.jitter_recovery
      PAL color-lossUse PAL color-loss effect-plr.colorloss
      -dev.colorloss
      - +
      ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Time Machine @@ -3752,7 +4043,7 @@      - + @@ -3775,7 +4066,7 @@ Developer Commands for more information.
    • Viewing TIA/console information overlaid on the TIA image. This option - can be enabled from the commandline or using the Alt-L key combo, + can be enabled from the command line or using the Alt-L key combo, and is extremely useful for viewing the current scanline count and associated frames per second, bankswitch and display formats, etc. The following shows an example of this information: @@ -3967,7 +4258,7 @@ Ms Pac-Man (Stella extended codes):

      Stella maintains a log of its operations when the program first starts up, and while it is running. In older releases, this information was only viewable from the - commandline. However, the current release allows + command line. However, the current release allows you to see this information from within the UI. This can be selected from the main Options menu, where it is labelled "System Logs". Clicking on the button will show a window similar to the following:

      @@ -3988,7 +4279,7 @@ Ms Pac-Man (Stella extended codes):

      The log levels are self-explanatory (None, Basic, Verbose). The "Print to console" option emulates the behaviour of older versions of Stella, whereby the logged output - is also shown on the commandline from which Stella was launched (if it was launched + is also shown on the command line from which Stella was launched (if it was launched in that fashion). Finally, the current contents of the system log can be saved to your home directory by clicking the "Save log to disk" button.


      @@ -4039,19 +4330,20 @@ Ms Pac-Man (Stella extended codes):

      Each block in a property file consists of a set of properties for a single game. Stella supports the properties described below:

      +

      Emulation Properties

      - +

    • ItemBrief descriptionFor more information,
      see CommandLine
      ItemBrief descriptionFor more information,
      see Command Line
      Font sizeSelf-explanatory-dbg.fontsize
      Font styleSelf-explanatory-dbg.fontstyle
      Debugger width/heightSelf-explanatory-dbg.res
      - + @@ -4279,19 +4577,46 @@ Ms Pac-Man (Stella extended codes):
      Cart.Type:Cart.Type Indicates the bank-switching type for the game. The value of this property must be either Auto or one of the following (for more information about bank-switching see Kevin Horton's 2600 bankswitching document or the documentation in each cartridge's source code file) types. Types marked as (¹) do currently have no reliable auto-detection, those marked as (²) - are not fully supported in the debugger: + are not fully supported in the debugger. @@ -4074,7 +4366,7 @@ Ms Pac-Man (Stella extended codes): - + @@ -4110,12 +4402,12 @@ Ms Pac-Man (Stella extended codes): - + - + - + - + - + - + - + - + - + - + - +
       Type DescriptionFile Extension
      (to force type)
      0840 8K ECONObanking .084, .0840
      BF CPUWIZ 256K .BF
      BFSC CPUWIZ 256K + RAM.BFS, .BFSC
      BUS Experimental.BUS
      CDF Chris, Darrell, Fred (includes CDFJ).CDF
      CDF Chris, Darrell, Fred (includes CDFJ/CDFJ+).CDF
      CM ¹Spectravideo CompuMate .CM
      CTY ²CDW - Chetiry .CTY
      CV CommaVid extra RAM .CV
      Cart.StartBank:Cart.StartBank Indicates which bank to use for reading the reset vector.
      Display.Format:Display.Format Indicates the television format the game was designed for. The value must be Auto or one of the following. Types marked as (¹) do currently have no reliable auto-detection. A format can be enforced @@ -4132,27 +4424,27 @@ Ms Pac-Man (Stella extended codes):
      Display.VCenter:Display.VCenter Indicates the offset for the vertical center of the display. The value must be n such that -20 <= n <= 20.
      Display.Phosphor:Display.Phosphor Indicates whether the phosphor effect should be emulated or not. The value must be Yes or No.
      Display.PPBlend:Display.PPBlend Indicates the amount of blending which will occur while using the phosphor effect. The value must be n such that 0 <= n <= 100. The default value is whatever is specified for tv.phosblend.
      Cart.Sound:Cart.Sound Indicates if the game should use 1 or 2 channels for sound output. All original Atari 2600 machines supported 1 channel only, but some homebrew games have been written to take advantage of stereo @@ -4165,37 +4457,42 @@ Ms Pac-Man (Stella extended codes):

      Note: Items marked as '*' are deprecated, and will probably be removed in a future release.

      --> +

      Console Properties

      - +

      - + - + - +
      Console.TVType:Console.TVType Indicates the default television setting for the game. The value must be Color or BW.
      Console.LeftDiff:Console.LeftDiff Indicates the default difficulty setting for the left player. The value must be A or B.
      Console.RightDiff:Console.RightDiff Indicates the default difficulty setting for the right player. The value must be A or B.

      +

      Controller Properties

      - +

      - + - + - + +
      Controller.Left:
      Controller.Right:
      + Controller.Left
      + Controller.Right
      +
      Indicates what type of controller the left and right player uses. The value must be either Auto or one of the following types. Types marked as (¹) do not have auto-detection yet. @@ -4215,14 +4512,15 @@ Ms Pac-Man (Stella extended codes):
      SaveKeyA 32K EEPROM for saving high scores, etc. (the EEPROM portion of an AtariVox).
      Genesis Sega Genesis controller, which can be used similar to a BoosterGrip, giving an extra button.
      CompuMate ¹Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).
      LightgunAtari XG-1 compatible Light Gun
      LightgunAtari XG-1 compatible Light Gun
      Mindlink ¹Mindlink controller.
      KidVid ¹KidVid controller, limitted suport (8, 9 and 0 start the games).
      KidVid ¹KidVid controller, limited support (8, 9 and 0 start the games).
      QuadTariQuadTari controller, limited support (see below).
      Console.SwapPorts:Console.SwapPorts Indicates that the left and right ports should be swapped internally. This is used for ROMs like 'Raiders of the Lost Ark' where the Player 0 joystick is plugged into the right joystick port. @@ -4230,7 +4528,7 @@ Ms Pac-Man (Stella extended codes):
      Controller.SwapPaddles:Controller.SwapPaddles Indicates that the left and right paddles in a particular port should be swapped. This is used for ROMs like 'Demons to Diamonds' where the default paddle is paddle 1, not @@ -4240,17 +4538,17 @@ Ms Pac-Man (Stella extended codes):
      Controller.PaddlesXCenter:Controller.PaddlesXCenter Defines the horizontal center of the paddles (range -10..30).
      Controller.PaddlesYCenter:Controller.PaddlesYCenter Defines the vertical center of the paddles (range -10..30).
      Controller.MouseAxis:Controller.MouseAxis Indicates how the mouse should emulate virtual controllers. In 'Auto' mode, the system decides how to best use the mouse. Otherwise, XY indicates how to use the X/Y axis (ie, 02 is paddle0/paddle2). @@ -4268,7 +4566,7 @@ Ms Pac-Man (Stella extended codes):
      7 MindLink 1
      An optional second parameter (default of 100) indicates how much - of the paddle range that the mouse should emulate. + of the paddle range the mouse should emulate.

      +

      QuadTari Properties

      - +

      - + + + +
      Cart.Name: + Controller.Left1
      + Controller.Left2
      + Controller.Right1
      + Controller.Right2
      +
      Indicates which controllers are plugged into one of the four QuadTari ports. + The value must be one of the following types. + + + + + + + +
       Type Description
      JoystickAtari's famous black joystick that was originally included with the system.
      Paddles Standard paddle controllers, only (up to 8) fire buttons supported for QuadTari.
      DrivingLooks like a paddle, but allows 360° movement. Only one unit per connector, unlike paddles which were sold in pairs.
      AtariVoxA SpeakJet based unlimited-vocabulary speech/sound synthesizer with 32K EEPROM.
      SaveKeyA 32K EEPROM for saving high scores, etc. (the EEPROM portion of an AtariVox).
      +
      + +

      Cartridge Properties

      +

      + +

      + + + - + - + - + - + - + diff --git a/docs/index_r77.html b/docs/index_r77.html index cc15b11ab..ed6e9bc84 100644 --- a/docs/index_r77.html +++ b/docs/index_r77.html @@ -58,7 +58,7 @@

      Stella for RetroN 77

      Atari 2600 VCS emulator

      -
      Release 6.2.1
      +
      Release 6.4

      Quick Navigation Guide


      diff --git a/src/cheat/CheatCodeDialog.cxx b/src/cheat/CheatCodeDialog.cxx index 09ac1cd3c..481dcbcd5 100644 --- a/src/cheat/CheatCodeDialog.cxx +++ b/src/cheat/CheatCodeDialog.cxx @@ -100,6 +100,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent, return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9'); }; myCheatInput->setTextFilter(f1, 1); + myCheatInput->setToolTip("See Stella documentation for details.", 1); addToFocusList(wid); diff --git a/src/common/EventHandlerSDL2.cxx b/src/common/EventHandlerSDL2.cxx index 2e8b60323..86d4dad89 100644 --- a/src/common/EventHandlerSDL2.cxx +++ b/src/common/EventHandlerSDL2.cxx @@ -27,6 +27,15 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem) { ASSERT_MAIN_THREAD; +#ifdef GUI_SUPPORT + { + ostringstream buf; + myQwertz = int('y') == int(SDL_GetKeyFromScancode(SDL_Scancode(KBDK_Z))); + buf << "Keyboard: " << (myQwertz ? "QWERTZ" : "QWERTY"); + Logger::debug(buf.str()); + } +#endif + #ifdef JOYSTICK_SUPPORT if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { @@ -36,6 +45,8 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem) } Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK"); #endif + + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -58,6 +69,23 @@ void EventHandlerSDL2::enableTextEvents(bool enable) SDL_StopTextInput(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandlerSDL2::copyText(const string& text) const +{ + SDL_SetClipboardText(text.c_str()); +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string EventHandlerSDL2::pasteText(string& text) const +{ + if(SDL_HasClipboardText()) + text = SDL_GetClipboardText(); + else + text = ""; + + return text; +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandlerSDL2::pollEvent() { diff --git a/src/common/EventHandlerSDL2.hxx b/src/common/EventHandlerSDL2.hxx index 2fea58371..0c5301749 100644 --- a/src/common/EventHandlerSDL2.hxx +++ b/src/common/EventHandlerSDL2.hxx @@ -44,6 +44,12 @@ class EventHandlerSDL2 : public EventHandler */ void enableTextEvents(bool enable) override; + /** + Clipboard methods. + */ + void copyText(const string& text) const override; + string pasteText(string& text) const override; + /** Collects and dispatches any pending SDL2 events. */ diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FBBackendSDL2.cxx similarity index 76% rename from src/common/FrameBufferSDL2.cxx rename to src/common/FBBackendSDL2.cxx index 24b038d01..643c099e9 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FBBackendSDL2.cxx @@ -27,11 +27,11 @@ #include "ThreadDebugging.hxx" #include "FBSurfaceSDL2.hxx" -#include "FrameBufferSDL2.hxx" +#include "FBBackendSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) - : FrameBuffer(osystem) +FBBackendSDL2::FBBackendSDL2(OSystem& osystem) + : myOSystem(osystem) { ASSERT_MAIN_THREAD; @@ -43,7 +43,7 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) Logger::error(buf.str()); throw runtime_error("FATAL ERROR"); } - Logger::debug("FrameBufferSDL2::FrameBufferSDL2 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 FBSurfaceSDL2 object) @@ -53,7 +53,7 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBufferSDL2::~FrameBufferSDL2() +FBBackendSDL2::~FBBackendSDL2() { ASSERT_MAIN_THREAD; @@ -61,12 +61,6 @@ FrameBufferSDL2::~FrameBufferSDL2() if(myRenderer) { - // Make sure to free surfaces/textures before destroying the renderer itself - // Most platforms are fine with doing this in either order, but it seems - // that OpenBSD in particular crashes when attempting to destroy textures - // *after* the renderer is already destroyed - freeSurfaces(); - SDL_DestroyRenderer(myRenderer); myRenderer = nullptr; } @@ -81,9 +75,9 @@ FrameBufferSDL2::~FrameBufferSDL2() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::queryHardware(vector& fullscreenRes, - vector& windowedRes, - VariantList& renderers) +void FBBackendSDL2::queryHardware(vector& fullscreenRes, + vector& windowedRes, + VariantList& renderers) { ASSERT_MAIN_THREAD; @@ -105,7 +99,7 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, string lastRes = ""; - for (int m = 0; m < numModes; m++) + for(int m = 0; m < numModes; ++m) { SDL_DisplayMode mode; ostringstream res; @@ -196,7 +190,7 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::isCurrentWindowPositioned() const +bool FBBackendSDL2::isCurrentWindowPositioned() const { ASSERT_MAIN_THREAD; @@ -205,7 +199,7 @@ bool FrameBufferSDL2::isCurrentWindowPositioned() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Common::Point FrameBufferSDL2::getCurrentWindowPos() const +Common::Point FBBackendSDL2::getCurrentWindowPos() const { ASSERT_MAIN_THREAD; @@ -217,7 +211,7 @@ Common::Point FrameBufferSDL2::getCurrentWindowPos() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Int32 FrameBufferSDL2::getCurrentDisplayIndex() const +Int32 FBBackendSDL2::getCurrentDisplayIndex() const { ASSERT_MAIN_THREAD; @@ -225,7 +219,8 @@ Int32 FrameBufferSDL2::getCurrentDisplayIndex() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) +bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode, + int winIdx, const Common::Point& winPos) { ASSERT_MAIN_THREAD; @@ -235,26 +230,22 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) const bool fullScreen = mode.fsIndex != -1; bool forceCreateRenderer = false; - - // Get windowed window's last display - Int32 displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt(getDisplayKey())); - // Get windowed window's last position - myWindowedPos = myOSystem.settings().getPoint(getPositionKey()); + Int32 displayIndex = std::min(myNumDisplays, winIdx); int posX, posY; myCenter = myOSystem.settings().getBool("center"); - if (myCenter) + if(myCenter) posX = posY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex); else { - posX = myWindowedPos.x; - posY = myWindowedPos.y; + posX = winPos.x; + posY = winPos.y; // Make sure the window is at least partially visibile int x0 = 0, y0 = 0, x1 = 0, y1 = 0; - for (int display = SDL_GetNumVideoDisplays() - 1; display >= 0; display--) + for(int display = SDL_GetNumVideoDisplays() - 1; display >= 0; --display) { SDL_Rect rect; @@ -266,22 +257,28 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) y1 = std::max(y1, rect.y + rect.h); } } - posX = BSPF::clamp(posX, x0 - Int32(mode.screen.w) + 50, x1 - 50); + posX = BSPF::clamp(posX, x0 - Int32(mode.screenS.w) + 50, x1 - 50); posY = BSPF::clamp(posY, y0 + 50, y1 - 50); } #ifdef ADAPTABLE_REFRESH_SUPPORT SDL_DisplayMode adaptedSdlMode; - const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh") - && gameRefreshRate() + const int gameRefreshRate = + myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0; + const bool shouldAdapt = fullScreen + && myOSystem.settings().getBool("tia.fs_refresh") + && gameRefreshRate // take care of 59.94 Hz - && refreshRate() % gameRefreshRate() != 0 && refreshRate() % (gameRefreshRate() - 1) != 0; - const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode); + && refreshRate() % gameRefreshRate != 0 + && refreshRate() % (gameRefreshRate - 1) != 0; + const bool adaptRefresh = shouldAdapt && + adaptRefreshRate(displayIndex, adaptedSdlMode); #else const bool adaptRefresh = false; #endif const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI - | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + | (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 @@ -291,8 +288,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) int w, h; SDL_GetWindowSize(myWindow, &w, &h); - if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h - || adaptRefresh) + if(d != displayIndex || uInt32(w) != mode.screenS.w || + uInt32(h) != mode.screenS.h || adaptRefresh) { SDL_DestroyWindow(myWindow); myWindow = nullptr; @@ -302,14 +299,14 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) if(myWindow) { // Even though window size stayed the same, the title may have changed - SDL_SetWindowTitle(myWindow, title.c_str()); + SDL_SetWindowTitle(myWindow, myScreenTitle.c_str()); SDL_SetWindowPosition(myWindow, posX, posY); } else { forceCreateRenderer = true; - myWindow = SDL_CreateWindow(title.c_str(), posX, posY, - mode.screen.w, mode.screen.h, flags); + myWindow = SDL_CreateWindow(myScreenTitle.c_str(), posX, posY, + mode.screenS.w, mode.screenS.h, flags); if(myWindow == nullptr) { string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError()); @@ -332,7 +329,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { ostringstream msg; - msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz"; + msg << "Display refresh rate changed to " + << adaptedSdlMode.refresh_rate << " Hz"; Logger::info(msg.str()); } } @@ -342,8 +340,11 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode) +bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex, + SDL_DisplayMode& adaptedSdlMode) { + ASSERT_MAIN_THREAD; + SDL_DisplayMode sdlMode; if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0) @@ -353,7 +354,8 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap } const int currentRefreshRate = sdlMode.refresh_rate; - const int wantedRefreshRate = gameRefreshRate(); + const int wantedRefreshRate = + myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0; // Take care of rounded refresh rates (e.g. 59.94 Hz) float factor = std::min(float(currentRefreshRate) / wantedRefreshRate, float(currentRefreshRate) / (wantedRefreshRate - 1)); @@ -397,8 +399,10 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::createRenderer(bool force) +bool FBBackendSDL2::createRenderer(bool force) { + ASSERT_MAIN_THREAD; + // A new renderer is only created when necessary: // - new myWindow (force = true) // - no renderer existing @@ -450,7 +454,7 @@ bool FrameBufferSDL2::createRenderer(bool force) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::setTitle(const string& title) +void FBBackendSDL2::setTitle(const string& title) { ASSERT_MAIN_THREAD; @@ -461,7 +465,7 @@ void FrameBufferSDL2::setTitle(const string& title) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string FrameBufferSDL2::about() const +string FBBackendSDL2::about() const { ASSERT_MAIN_THREAD; @@ -483,7 +487,7 @@ string FrameBufferSDL2::about() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::showCursor(bool show) +void FBBackendSDL2::showCursor(bool show) { ASSERT_MAIN_THREAD; @@ -491,7 +495,7 @@ void FrameBufferSDL2::showCursor(bool show) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::grabMouse(bool grab) +void FBBackendSDL2::grabMouse(bool grab) { ASSERT_MAIN_THREAD; @@ -499,7 +503,7 @@ void FrameBufferSDL2::grabMouse(bool grab) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::fullScreen() const +bool FBBackendSDL2::fullScreen() const { ASSERT_MAIN_THREAD; @@ -511,7 +515,7 @@ bool FrameBufferSDL2::fullScreen() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int FrameBufferSDL2::refreshRate() const +int FBBackendSDL2::refreshRate() const { ASSERT_MAIN_THREAD; @@ -528,20 +532,7 @@ int FrameBufferSDL2::refreshRate() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int FrameBufferSDL2::gameRefreshRate() const -{ - if(myOSystem.hasConsole()) - { - const string format = myOSystem.console().getFormatString(); - const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60"; - - return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz - } - return 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::renderToScreen() +void FBBackendSDL2::renderToScreen() { ASSERT_MAIN_THREAD; @@ -550,7 +541,7 @@ void FrameBufferSDL2::renderToScreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::setWindowIcon() +void FBBackendSDL2::setWindowIcon() { #if !defined(BSPF_MACOS) && !defined(RETRON77) #include "stella_icon.hxx" @@ -564,19 +555,20 @@ void FrameBufferSDL2::setWindowIcon() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -unique_ptr FrameBufferSDL2::createSurface( +unique_ptr FBBackendSDL2::createSurface( uInt32 w, uInt32 h, - FrameBuffer::ScalingInterpolation interpolation, + ScalingInterpolation inter, const uInt32* data ) const { - return make_unique(const_cast(*this), w, h, interpolation, data); + return make_unique + (const_cast(*this), w, h, inter, data); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch, - const Common::Rect& rect) const +void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch, + const Common::Rect& rect) const { ASSERT_MAIN_THREAD; @@ -588,7 +580,7 @@ void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::clear() +void FBBackendSDL2::clear() { ASSERT_MAIN_THREAD; @@ -596,49 +588,34 @@ void FrameBufferSDL2::clear() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SDL_Renderer* FrameBufferSDL2::renderer() -{ - return myRenderer; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::isInitialized() const -{ - return myRenderer != nullptr; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const SDL_PixelFormat& FrameBufferSDL2::pixelFormat() const -{ - return *myPixelFormat; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::detectFeatures() +void FBBackendSDL2::detectFeatures() { myRenderTargetSupport = detectRenderTargetSupport(); - if (myRenderer) { - if (!myRenderTargetSupport) { - Logger::info("Render targets are not supported --- QIS not available"); - } - } + if(myRenderer && !myRenderTargetSupport) + Logger::info("Render targets are not supported --- QIS not available"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::detectRenderTargetSupport() +bool FBBackendSDL2::detectRenderTargetSupport() { - if (myRenderer == nullptr) return false; + ASSERT_MAIN_THREAD; + + if(myRenderer == nullptr) + return false; SDL_RendererInfo info; - SDL_GetRendererInfo(myRenderer, &info); - if (!(info.flags & SDL_RENDERER_TARGETTEXTURE)) return false; + if(!(info.flags & SDL_RENDERER_TARGETTEXTURE)) + return false; - SDL_Texture* tex = SDL_CreateTexture(myRenderer, myPixelFormat->format, SDL_TEXTUREACCESS_TARGET, 16, 16); + SDL_Texture* tex = + SDL_CreateTexture(myRenderer, myPixelFormat->format, + SDL_TEXTUREACCESS_TARGET, 16, 16); - if (!tex) return false; + if(!tex) + return false; int sdlError = SDL_SetRenderTarget(myRenderer, tex); SDL_SetRenderTarget(myRenderer, nullptr); @@ -649,20 +626,17 @@ bool FrameBufferSDL2::detectRenderTargetSupport() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::hasRenderTargetSupport() const +void FBBackendSDL2::determineDimensions() { - return myRenderTargetSupport; -} + ASSERT_MAIN_THREAD; -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::determineDimensions() -{ SDL_GetWindowSize(myWindow, &myWindowW, &myWindowH); - if (myRenderer == nullptr) { + if(myRenderer == nullptr) + { myRenderW = myWindowW; myRenderH = myWindowH; - } else { - SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH); } + else + SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH); } diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FBBackendSDL2.hxx similarity index 75% rename from src/common/FrameBufferSDL2.hxx rename to src/common/FBBackendSDL2.hxx index 0b3386d08..67a5a2a57 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FBBackendSDL2.hxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#ifndef FRAMEBUFFER_SDL2_HXX -#define FRAMEBUFFER_SDL2_HXX +#ifndef FB_BACKEND_SDL2_HXX +#define FB_BACKEND_SDL2_HXX #include "SDL_lib.hxx" @@ -24,27 +24,55 @@ class OSystem; class FBSurfaceSDL2; #include "bspf.hxx" -#include "FrameBuffer.hxx" +#include "FBBackend.hxx" /** - This class implements a standard SDL2 2D, hardware accelerated framebuffer. - Behind the scenes, it may be using Direct3D, OpenGL(ES), etc. + 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 FrameBufferSDL2 : public FrameBuffer +class FBBackendSDL2 : public FBBackend { public: /** Creates a new SDL2 framebuffer */ - explicit FrameBufferSDL2(OSystem& osystem); - ~FrameBufferSDL2() override; + explicit FBBackendSDL2(OSystem& osystem); + ~FBBackendSDL2() override; - ////////////////////////////////////////////////////////////////////// - // The following are derived from public methods in FrameBuffer.hxx - ////////////////////////////////////////////////////////////////////// + public: + /** + Get a pointer to the SDL renderer. + */ + SDL_Renderer* renderer() { return myRenderer; } + /** + Is the renderer initialized? + */ + bool isInitialized() const { return myRenderer != nullptr; } + + /** + Get the SDL pixel format. + */ + const SDL_PixelFormat& pixelFormat() const { return *myPixelFormat; } + + /** + Does the renderer support render targets? + */ + bool hasRenderTargetSupport() const { return myRenderTargetSupport; } + + /** + Transform from window to renderer coordinates, x direction + */ + int scaleX(int x) const override { return (x * myRenderW) / myWindowW; } + + /** + Transform from window to renderer coordinates, y direction + */ + int scaleY(int y) const override { return (y * myRenderH) / myWindowH; } + + protected: /** Updates window title. @@ -93,7 +121,8 @@ class FrameBufferSDL2 : public FrameBuffer @param pitch The pitch (in bytes) for the pixel data @param rect The bounding rectangle for the buffer */ - void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const override; + void readPixels(uInt8* buffer, uInt32 pitch, + const Common::Rect& rect) const override; /** This method is called to query if the current window is not centered @@ -110,6 +139,7 @@ class FrameBufferSDL2 : public FrameBuffer @return The position of the currently displayed window */ Common::Point getCurrentWindowPos() const override; + /** This method is called to query the video hardware for the index of the display the current window is displayed on @@ -124,40 +154,6 @@ class FrameBufferSDL2 : public FrameBuffer */ void clear() override; - /** - Get a pointer to the SDL renderer. - */ - SDL_Renderer* renderer(); - - /** - Get the SDL pixel format. - */ - const SDL_PixelFormat& pixelFormat() const; - - /** - Is the renderer initialized? - */ - bool isInitialized() const; - - /** - Does the renderer support render targets? - */ - bool hasRenderTargetSupport() const; - - /** - Transform from window to renderer coordinates, x direction - */ - int scaleX(int x) const override { return (x * myRenderW) / myWindowW; } - - /** - Transform from window to renderer coordinates, y direction - */ - int scaleY(int y) const override { return (y * myRenderH) / myWindowH; } - - protected: - ////////////////////////////////////////////////////////////////////// - // The following are derived from protected methods in FrameBuffer.hxx - ////////////////////////////////////////////////////////////////////// /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. Since several @@ -174,45 +170,28 @@ class FrameBufferSDL2 : public FrameBuffer /** This method is called to change to the given video mode. - @param title The title for the created window - @param mode The video mode to use + @param mode The video mode to use + @param winIdx The display/monitor that the window last opened on + @param winPos The position that the window last opened at @return False on any errors, else true */ - bool setVideoMode(const string& title, const VideoMode& mode) override; - - /** - Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode - - @param displayIndex The display which should be checked - @param adaptedSdlMode The best matching mode if the refresh rate should be changed - - @return True if the refresh rate should be changed - */ - bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); - - /** - Create a new renderer if required - - @param force If true, force new renderer creation - - @return False on any errors, else true - */ - bool createRenderer(bool force); + bool setVideoMode(const VideoModeHandler::Mode& mode, + int winIdx, const Common::Point& winPos) override; /** This method is called to create a surface with the given attributes. - @param w The requested width of the new surface. - @param h The requested height of the new surface. - @param interpolation Interpolation mode - @param data If non-null, use the given data values as a static surface + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param inter Interpolation mode + @param data If non-null, use the given data values as a static surface */ unique_ptr createSurface( uInt32 w, uInt32 h, - FrameBuffer::ScalingInterpolation interpolation, + ScalingInterpolation inter, const uInt32* data ) const override; @@ -222,28 +201,49 @@ class FrameBufferSDL2 : public FrameBuffer void grabMouse(bool grab) override; /** - Set the icon for the main SDL window. - */ - void setWindowIcon() override; - - /** - This method is called to provide information about the FrameBuffer. + This method is called to provide information about the backend. */ string about() const override; + /** + Create a new renderer if required. + + @param force If true, force new renderer creation + + @return False on any errors, else true + */ + bool createRenderer(bool force); + /** This method must be called after all drawing is done, and indicates that the buffers should be pushed to the physical screen. */ void renderToScreen() override; + /** + Retrieve the current display's refresh rate, or 0 if no window. + */ + int refreshRate() const override; + + /** + Checks if the display refresh rate should be adapted to game refresh + rate in (real) fullscreen mode. + + @param displayIndex The display which should be checked + @param adaptedSdlMode The best matching mode if the refresh rate + should be changed + + @return True if the refresh rate should be changed + */ + bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode); + /** After the renderer has been created, detect the features it supports. */ void detectFeatures(); /** - Detect render target support; + Detect render target support. */ bool detectRenderTargetSupport(); @@ -253,16 +253,13 @@ class FrameBufferSDL2 : public FrameBuffer void determineDimensions(); /** - Retrieve the current display's refresh rate, or 0 if no window + Set the icon for the main SDL window. */ - int refreshRate() const override; - - /** - Retrieve the current game's refresh rate, or 60 if no game - */ - int gameRefreshRate() const; + void setWindowIcon(); private: + OSystem& myOSystem; + // The SDL video buffer SDL_Window* myWindow{nullptr}; SDL_Renderer* myRenderer{nullptr}; @@ -273,22 +270,25 @@ class FrameBufferSDL2 : public FrameBuffer // Center setting of current window bool myCenter{false}; - // last position of windowed window - Common::Point myWindowedPos; - // Does the renderer support render targets? bool myRenderTargetSupport{false}; + // Title of the main window/screen + string myScreenTitle; + + // Number of displays + int myNumDisplays{1}; + // Window and renderer dimensions int myWindowW{0}, myWindowH{0}, myRenderW{0}, myRenderH{0}; private: // Following constructors and assignment operators not supported - FrameBufferSDL2() = delete; - FrameBufferSDL2(const FrameBufferSDL2&) = delete; - FrameBufferSDL2(FrameBufferSDL2&&) = delete; - FrameBufferSDL2& operator=(const FrameBufferSDL2&) = delete; - FrameBufferSDL2& operator=(FrameBufferSDL2&&) = delete; + FBBackendSDL2() = delete; + FBBackendSDL2(const FBBackendSDL2&) = delete; + FBBackendSDL2(FBBackendSDL2&&) = delete; + FBBackendSDL2& operator=(const FBBackendSDL2&) = delete; + FBBackendSDL2& operator=(FBBackendSDL2&&) = delete; }; #endif diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index 94483a22b..7f0ddb7d7 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -22,16 +22,16 @@ #include "sdl_blitter/BlitterFactory.hxx" namespace { - BlitterFactory::ScalingAlgorithm scalingAlgorithm(FrameBuffer::ScalingInterpolation interpolation) + BlitterFactory::ScalingAlgorithm scalingAlgorithm(ScalingInterpolation inter) { - switch (interpolation) { - case FrameBuffer::ScalingInterpolation::none: + switch (inter) { + case ScalingInterpolation::none: return BlitterFactory::ScalingAlgorithm::nearestNeighbour; - case FrameBuffer::ScalingInterpolation::blur: + case ScalingInterpolation::blur: return BlitterFactory::ScalingAlgorithm::bilinear; - case FrameBuffer::ScalingInterpolation::sharp: + case ScalingInterpolation::sharp: return BlitterFactory::ScalingAlgorithm::quasiInteger; default: @@ -41,12 +41,12 @@ namespace { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, +FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height, - FrameBuffer::ScalingInterpolation interpolation, + ScalingInterpolation inter, const uInt32* staticData) - : myFB(buffer), - myInterpolationMode(interpolation) + : myBackend(backend), + myInterpolationMode(inter) { createSurface(width, height, staticData); } @@ -104,41 +104,49 @@ const Common::Rect& FBSurfaceSDL2::dstRect() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setSrcPos(uInt32 x, uInt32 y) { - if(x != static_cast(mySrcR.x) || y != static_cast(mySrcR.y)) - { - setSrcPosInternal(x, y); + if(setSrcPosInternal(x, y)) reinitializeBlitter(); - } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h) { - if(w != static_cast(mySrcR.w) || h != static_cast(mySrcR.h)) - { - setSrcSizeInternal(w, h); + if(setSrcSizeInternal(w, h)) + reinitializeBlitter(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::setSrcRect(const Common::Rect& r) +{ + const bool posChanged = setSrcPosInternal(r.x(), r.y()), + sizeChanged = setSrcSizeInternal(r.w(), r.h()); + + if(posChanged || sizeChanged) reinitializeBlitter(); - } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setDstPos(uInt32 x, uInt32 y) { - if(x != static_cast(myDstR.x) || y != static_cast(myDstR.y)) - { - setDstPosInternal(x, y); + if(setDstPosInternal(x, y)) reinitializeBlitter(); - } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h) { - if(w != static_cast(myDstR.w) || h != static_cast(myDstR.h)) - { - setDstSizeInternal(w, h); + if(setDstSizeInternal(w, h)) + reinitializeBlitter(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::setDstRect(const Common::Rect& r) +{ + const bool posChanged = setDstPosInternal(r.x(), r.y()), + sizeChanged = setDstSizeInternal(r.w(), r.h()); + + if(posChanged || sizeChanged) reinitializeBlitter(); - } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -176,6 +184,22 @@ void FBSurfaceSDL2::invalidate() SDL_FillRect(mySurface, nullptr, 0); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) +{ + ASSERT_MAIN_THREAD; + + // Clear the rectangle + SDL_Rect tmp; + tmp.x = x; + tmp.y = y; + tmp.w = w; + tmp.h = h; + // Note: Transparency has to be 0 to clear the rectangle foreground + // without affecting the background display. + SDL_FillRect(mySurface, &tmp, 0); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::free() { @@ -214,7 +238,7 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, ASSERT_MAIN_THREAD; // Create a surface in the same format as the parent GL class - const SDL_PixelFormat& pf = myFB.pixelFormat(); + const SDL_PixelFormat& pf = myBackend.pixelFormat(); mySurface = SDL_CreateRGBSurface(0, width, height, pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask); @@ -242,11 +266,13 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::reinitializeBlitter() { - if (!myBlitter && myFB.isInitialized()) - myBlitter = BlitterFactory::createBlitter(myFB, scalingAlgorithm(myInterpolationMode)); + if (!myBlitter && myBackend.isInitialized()) + myBlitter = BlitterFactory::createBlitter( + myBackend, scalingAlgorithm(myInterpolationMode)); if (myBlitter) - myBlitter->reinitialize(mySrcR, myDstR, myAttributes, myIsStatic ? mySurface : nullptr); + myBlitter->reinitialize(mySrcR, myDstR, myAttributes, + myIsStatic ? mySurface : nullptr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -256,7 +282,7 @@ void FBSurfaceSDL2::applyAttributes() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceSDL2::setScalingInterpolation(FrameBuffer::ScalingInterpolation interpolation) +void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation) { if (interpolation == myInterpolationMode) return; diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index 62e9d96a2..d8bfa0029 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -20,7 +20,7 @@ #include "bspf.hxx" #include "FBSurface.hxx" -#include "FrameBufferSDL2.hxx" +#include "FBBackendSDL2.hxx" #include "sdl_blitter/Blitter.hxx" /** @@ -32,9 +32,8 @@ class FBSurfaceSDL2 : public FBSurface { public: - FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height, - FrameBuffer::ScalingInterpolation interpolation, - const uInt32* staticData); + FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height, + ScalingInterpolation inter, const uInt32* staticData); ~FBSurfaceSDL2() override; // Most of the surface drawing primitives are implemented in FBSurface; @@ -49,38 +48,63 @@ class FBSurfaceSDL2 : public FBSurface const Common::Rect& dstRect() const override; void setSrcPos(uInt32 x, uInt32 y) override; void setSrcSize(uInt32 w, uInt32 h) override; + void setSrcRect(const Common::Rect& r) override; void setDstPos(uInt32 x, uInt32 y) override; void setDstSize(uInt32 w, uInt32 h) override; + void setDstRect(const Common::Rect& r) override; + void setVisible(bool visible) override; void translateCoords(Int32& x, Int32& y) const override; bool render() override; void invalidate() override; + void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override; + void free() override; void reload() override; void resize(uInt32 width, uInt32 height) override; - void setScalingInterpolation(FrameBuffer::ScalingInterpolation) override; + void setScalingInterpolation(ScalingInterpolation) override; protected: void applyAttributes() override; private: - inline void setSrcPosInternal(uInt32 x, uInt32 y) { - mySrcR.x = x; mySrcR.y = y; - mySrcGUIR.moveTo(x, y); + inline bool setSrcPosInternal(uInt32 x, uInt32 y) { + if(x != static_cast(mySrcR.x) || y != static_cast(mySrcR.y)) + { + mySrcR.x = x; mySrcR.y = y; + mySrcGUIR.moveTo(x, y); + return true; + } + return false; } - inline void setSrcSizeInternal(uInt32 w, uInt32 h) { - mySrcR.w = w; mySrcR.h = h; - mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h); + inline bool setSrcSizeInternal(uInt32 w, uInt32 h) { + if(w != static_cast(mySrcR.w) || h != static_cast(mySrcR.h)) + { + mySrcR.w = w; mySrcR.h = h; + mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h); + return true; + } + return false; } - inline void setDstPosInternal(uInt32 x, uInt32 y) { - myDstR.x = x; myDstR.y = y; - myDstGUIR.moveTo(x, y); + inline bool setDstPosInternal(uInt32 x, uInt32 y) { + if(x != static_cast(myDstR.x) || y != static_cast(myDstR.y)) + { + myDstR.x = x; myDstR.y = y; + myDstGUIR.moveTo(x, y); + return true; + } + return false; } - inline void setDstSizeInternal(uInt32 w, uInt32 h) { - myDstR.w = w; myDstR.h = h; - myDstGUIR.setWidth(w); myDstGUIR.setHeight(h); + inline bool setDstSizeInternal(uInt32 w, uInt32 h) { + if(w != static_cast(myDstR.w) || h != static_cast(myDstR.h)) + { + myDstR.w = w; myDstR.h = h; + myDstGUIR.setWidth(w); myDstGUIR.setHeight(h); + return true; + } + return false; } void createSurface(uInt32 width, uInt32 height, const uInt32* data); @@ -95,14 +119,14 @@ class FBSurfaceSDL2 : public FBSurface FBSurfaceSDL2& operator=(FBSurfaceSDL2&&) = delete; private: - FrameBufferSDL2& myFB; + FBBackendSDL2& myBackend; unique_ptr myBlitter; - FrameBuffer::ScalingInterpolation myInterpolationMode - {FrameBuffer::ScalingInterpolation::none}; + ScalingInterpolation myInterpolationMode + {ScalingInterpolation::none}; SDL_Surface* mySurface{nullptr}; - SDL_Rect mySrcR{0, 0, 0, 0}, myDstR{0, 0, 0, 0}; + SDL_Rect mySrcR{-1, -1, -1, -1}, myDstR{-1, -1, -1, -1}; bool myIsVisible{true}; bool myIsStatic{false}; diff --git a/src/common/JoyMap.cxx b/src/common/JoyMap.cxx index 266dd5e74..6b8c95b42 100644 --- a/src/common/JoyMap.cxx +++ b/src/common/JoyMap.cxx @@ -16,6 +16,10 @@ //============================================================================ #include "JoyMap.hxx" +#include "jsonDefinitions.hxx" +#include "Logger.hxx" + +using json = nlohmann::json; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JoyMap::add(const Event::Type event, const JoyMapping& mapping) @@ -183,67 +187,105 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string JoyMap::saveMapping(const EventMode mode) const +json JoyMap::saveMapping(const EventMode mode) const { - using MapType = std::pair; - std::vector sortedMap(myMap.begin(), myMap.end()); + json eventMappings = json::array(); - std::sort(sortedMap.begin(), sortedMap.end(), - [](const MapType& a, const MapType& b) - { - // Event::Type first - if(a.second != b.second) - return a.second < b.second; + for (auto& item: myMap) { + if (item.first.mode != mode) continue; - if(a.first.button != b.first.button) - return a.first.button < b.first.button; + json eventMapping = json::object(); - if(a.first.axis != b.first.axis) - return a.first.axis < b.first.axis; + eventMapping["event"] = item.second; - if(a.first.adir != b.first.adir) - return a.first.adir < b.first.adir; + if (item.first.button != JOY_CTRL_NONE) eventMapping["button"] = item.first.button; - if(a.first.hat != b.first.hat) - return a.first.hat < b.first.hat; - - return a.first.hdir < b.first.hdir; + if (item.first.axis != JoyAxis::NONE) { + eventMapping["axis"] = item.first.axis; + eventMapping["axisDirection"] = item.first.adir; } - ); - ostringstream buf; - - for (auto item : sortedMap) - { - if (item.first.mode == mode) - { - if (buf.str() != "") - buf << "|"; - buf << item.second << ":" << item.first.button << "," - << int(item.first.axis) << "," << int(item.first.adir) << "," - << item.first.hat << "," << int(item.first.hdir); + if (item.first.hat != -1) { + eventMapping["hat"] = item.first.hat; + eventMapping["hatDirection"] = item.first.hdir; } + + eventMappings.push_back(eventMapping); } - return buf.str(); + + return eventMappings; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int JoyMap::loadMapping(string& list, const EventMode mode) +int JoyMap::loadMapping(const json& eventMappings, const EventMode mode) { + int i = 0; + + for (const json& eventMapping: eventMappings) { + int button = eventMapping.contains("button") ? eventMapping.at("button").get() : JOY_CTRL_NONE; + JoyAxis axis = eventMapping.contains("axis") ? eventMapping.at("axis").get() : JoyAxis::NONE; + JoyDir axisDirection = eventMapping.contains("axis") ? eventMapping.at("axisDirection").get() : JoyDir::NONE; + int hat = eventMapping.contains("hat") ? eventMapping.at("hat").get() : -1; + JoyHatDir hatDirection = eventMapping.contains("hat") ? eventMapping.at("hatDirection").get() : JoyHatDir::CENTER; + + try { + add( + eventMapping.at("event").get(), + mode, + button, + axis, + axisDirection, + hat, + hatDirection + ); + + i++; + } catch (json::exception) { + Logger::error("ignoring invalid joystick event"); + } + } + + return i; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +json JoyMap::convertLegacyMapping(string list) +{ + json eventMappings = json::array(); + // Since istringstream swallows whitespace, we have to make the // delimiters be spaces std::replace(list.begin(), list.end(), '|', ' '); std::replace(list.begin(), list.end(), ':', ' '); std::replace(list.begin(), list.end(), ',', ' '); + istringstream buf(list); - int event, button, axis, adir, hat, hdir, i = 0; + int event, button, axis, adir, hat, hdir; while (buf >> event && buf >> button && buf >> axis && buf >> adir - && buf >> hat && buf >> hdir && ++i) - add(Event::Type(event), EventMode(mode), button, JoyAxis(axis), JoyDir(adir), hat, JoyHatDir(hdir)); + && buf >> hat && buf >> hdir) + { + json eventMapping = json::object(); - return i; + eventMapping["event"] = Event::Type(event); + + if (button != JOY_CTRL_NONE) eventMapping["button"] = button; + + if (JoyAxis(axis) != JoyAxis::NONE) { + eventMapping["axis"] = JoyAxis(axis); + eventMapping["axisDirection"] = JoyDir(adir); + } + + if (hat != -1) { + eventMapping["hat"] = hat; + eventMapping["hatDirection"] = JoyHatDir(hdir); + } + + eventMappings.push_back(eventMapping); + } + + return eventMappings; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/JoyMap.hxx b/src/common/JoyMap.hxx index e3cc7ff7a..6bf87009e 100644 --- a/src/common/JoyMap.hxx +++ b/src/common/JoyMap.hxx @@ -22,6 +22,7 @@ #include "Event.hxx" #include "EventHandlerConstants.hxx" +#include "json.hxx" /** This class handles controller mappings in Stella. @@ -110,8 +111,10 @@ class JoyMap JoyMappingArray getEventMapping(const Event::Type event, const EventMode mode) const; - string saveMapping(const EventMode mode) const; - int loadMapping(string& list, const EventMode mode); + nlohmann::json saveMapping(const EventMode mode) const; + int loadMapping(const nlohmann::json& eventMappings, const EventMode mode); + + static nlohmann::json convertLegacyMapping(string list); /** Erase all mappings for given mode */ void eraseMode(const EventMode mode); diff --git a/src/common/KeyMap.cxx b/src/common/KeyMap.cxx index 47b34dc9c..2e493b331 100644 --- a/src/common/KeyMap.cxx +++ b/src/common/KeyMap.cxx @@ -16,8 +16,12 @@ //============================================================================ #include "KeyMap.hxx" +#include "Logger.hxx" +#include "jsonDefinitions.hxx" #include +using json = nlohmann::json; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyMap::add(const Event::Type event, const Mapping& mapping) { @@ -169,54 +173,74 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string KeyMap::saveMapping(const EventMode mode) const +json KeyMap::saveMapping(const EventMode mode) const { - using MapType = std::pair; - std::vector sortedMap(myMap.begin(), myMap.end()); + json mappings = json::array(); - std::sort(sortedMap.begin(), sortedMap.end(), - [](const MapType& a, const MapType& b) - { - // Event::Type first - if(a.second != b.second) - return a.second < b.second; + for (auto item : myMap) { + if (item.first.mode != mode) continue; - if(a.first.key != b.first.key) - return a.first.key < b.first.key; + json mapping = json::object(); - return a.first.mod < b.first.mod; - } - ); + mapping["event"] = item.second; + mapping["key"] = item.first.key; - ostringstream buf; + if (item.first.mod != StellaMod::KBDM_NONE) + mapping["mod"] = item.first.mod; - for (auto item : sortedMap) - { - if (item.first.mode == mode) - { - if (buf.str() != "") - buf << "|"; - buf << item.second << ":" << item.first.key << "," << item.first.mod; - } + mappings.push_back(mapping); } - return buf.str(); + + return mappings; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int KeyMap::loadMapping(string& list, const EventMode mode) +int KeyMap::loadMapping(const json& mappings, const EventMode mode) { + int i = 0; + + for (const json& mapping: mappings) { + try { + add( + mapping.at("event").get(), + mode, + mapping.at("key").get(), + mapping.contains("mod") ? mapping.at("mod").get() : StellaMod::KBDM_NONE + ); + + i++; + } catch (json::exception) { + Logger::error("ignoring bad keyboard mapping"); + } + } + + return i; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +json KeyMap::convertLegacyMapping(string list) { + json convertedMapping = json::array(); + // Since istringstream swallows whitespace, we have to make the // delimiters be spaces std::replace(list.begin(), list.end(), '|', ' '); std::replace(list.begin(), list.end(), ':', ' '); std::replace(list.begin(), list.end(), ',', ' '); istringstream buf(list); - int event, key, mod, i = 0; + int event, key, mod; - while (buf >> event && buf >> key && buf >> mod && ++i) - add(Event::Type(event), mode, key, mod); + while (buf >> event && buf >> key && buf >> mod) { + json mapping = json::object(); - return i; + mapping["event"] = Event::Type(event); + mapping["key"] = StellaKey(key); + + if (StellaMod(mod) != StellaMod::KBDM_NONE) mapping["mod"] = StellaMod(mod); + + convertedMapping.push_back(mapping); + } + + return convertedMapping; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/KeyMap.hxx b/src/common/KeyMap.hxx index 0b7eff2fe..b5805225f 100644 --- a/src/common/KeyMap.hxx +++ b/src/common/KeyMap.hxx @@ -22,6 +22,7 @@ #include "Event.hxx" #include "EventHandlerConstants.hxx" #include "StellaKeys.hxx" +#include "json.hxx" /** This class handles keyboard mappings in Stella. @@ -86,8 +87,10 @@ class KeyMap MappingArray getEventMapping(const Event::Type event, const EventMode mode) const; - string saveMapping(const EventMode mode) const; - int loadMapping(string& list, const EventMode mode); + nlohmann::json saveMapping(const EventMode mode) const; + int loadMapping(const nlohmann::json& mapping, const EventMode mode); + + static nlohmann::json convertLegacyMapping(string list); /** Erase all mappings for given mode */ void eraseMode(const EventMode mode); diff --git a/src/common/MediaFactory.hxx b/src/common/MediaFactory.hxx index ad18685cb..8360d9b38 100644 --- a/src/common/MediaFactory.hxx +++ b/src/common/MediaFactory.hxx @@ -51,10 +51,10 @@ #if defined(__LIB_RETRO__) #include "EventHandlerLIBRETRO.hxx" - #include "FrameBufferLIBRETRO.hxx" + #include "FBBackendLIBRETRO.hxx" #elif defined(SDL_SUPPORT) #include "EventHandlerSDL2.hxx" - #include "FrameBufferSDL2.hxx" + #include "FBBackendSDL2.hxx" #else #error Unsupported backend! #endif @@ -128,12 +128,12 @@ class MediaFactory #endif } - static unique_ptr createVideo(OSystem& osystem) + static unique_ptr createVideoBackend(OSystem& osystem) { #if defined(__LIB_RETRO__) - return make_unique(osystem); + return make_unique(osystem); #elif defined(SDL_SUPPORT) - return make_unique(osystem); + return make_unique(osystem); #else #error Unsupported platform for FrameBuffer! #endif diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index f9c616921..323caea1c 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -22,12 +22,13 @@ #include "Settings.hxx" #include "EventHandler.hxx" #include "PJoystickHandler.hxx" +#include "Logger.hxx" #ifdef GUI_SUPPORT #include "DialogContainer.hxx" #endif -static constexpr char CTRL_DELIM = '^'; +using json = nlohmann::json; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystickHandler::PhysicalJoystickHandler( @@ -35,25 +36,54 @@ PhysicalJoystickHandler::PhysicalJoystickHandler( : myOSystem(system), myHandler(handler) { - Int32 version = myOSystem.settings().getInt("event_ver"); - // Load previously saved joystick mapping (if any) from settings - istringstream buf(myOSystem.settings().getString("joymap")); + if(myOSystem.settings().getInt("event_ver") != Event::VERSION) { + Logger::info("event version mismatch; dropping previous joystick mappings"); + + return; + } + + json mappings; + const string& serializedMapping = myOSystem.settings().getString("joymap"); + + try { + mappings = json::parse(serializedMapping); + } catch (json::exception) { + Logger::info("converting legacy joystick mappings"); + + mappings = convertLegacyMapping(serializedMapping); + } + + for (const json& mapping: mappings) { + if (!mapping.contains("name")) { + Logger::error("ignoring bad joystick mapping"); + continue; + } + + myDatabase.emplace(mapping.at("name").get(), StickInfo(mapping)); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +json PhysicalJoystickHandler::convertLegacyMapping(const string& mapping) +{ + constexpr char CTRL_DELIM = '^'; + + istringstream buf(mapping); string joymap, joyname; - // First compare if event list version has changed, and disregard the entire - // mapping if true getline(buf, joymap, CTRL_DELIM); // event list size, ignore - if(version == Event::VERSION) + + json convertedMapping = json::array(); + + while(getline(buf, joymap, CTRL_DELIM)) { - // Otherwise, put each joystick mapping entry into the database - while(getline(buf, joymap, CTRL_DELIM)) - { - istringstream namebuf(joymap); - getline(namebuf, joyname, PhysicalJoystick::MODE_DELIM); - if(joyname.length() != 0) - myDatabase.emplace(joyname, StickInfo(joymap)); - } + istringstream namebuf(joymap); + getline(namebuf, joyname, PhysicalJoystick::MODE_DELIM); + + convertedMapping.push_back(PhysicalJoystick::convertLegacyMapping(joymap, joyname)); } + + return convertedMapping; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -526,15 +556,16 @@ void PhysicalJoystickHandler::saveMapping() { // Save the joystick mapping hash table, making sure to update it with // any changes that have been made during the program run - ostringstream joybuf; + json mapping = json::array(); for(const auto& i: myDatabase) { - const string& map = i.second.joy ? i.second.joy->getMap() : i.second.mapping; - if(map != "") - joybuf << CTRL_DELIM << map; + json map = i.second.joy ? i.second.joy->getMap() : i.second.mapping; + + if (!map.is_null()) mapping.emplace_back(map); } - myOSystem.settings().setValue("joymap", joybuf.str()); + + myOSystem.settings().setValue("joymap", mapping.dump()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PJoystickHandler.hxx b/src/common/PJoystickHandler.hxx index fe7aad585..8e43bdf97 100644 --- a/src/common/PJoystickHandler.hxx +++ b/src/common/PJoystickHandler.hxx @@ -28,6 +28,7 @@ class Event; #include "EventHandlerConstants.hxx" #include "PhysicalJoystick.hxx" #include "Variant.hxx" +#include "json.hxx" using PhysicalJoystickPtr = shared_ptr; @@ -48,10 +49,10 @@ class PhysicalJoystickHandler private: struct StickInfo { - StickInfo(const string& map = EmptyString, PhysicalJoystickPtr stick = nullptr) + StickInfo(const nlohmann::json& map = nullptr, PhysicalJoystickPtr stick = nullptr) : mapping(map), joy(std::move(stick)) {} - string mapping; + nlohmann::json mapping; PhysicalJoystickPtr joy; friend ostream& operator<<(ostream& os, const StickInfo& si) { @@ -63,6 +64,8 @@ class PhysicalJoystickHandler public: PhysicalJoystickHandler(OSystem& system, EventHandler& handler); + static nlohmann::json convertLegacyMapping(const string& mapping); + /** Return stick ID on success, -1 on failure. */ int add(const PhysicalJoystickPtr& stick); bool remove(int id); diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 7532a1632..108a620b9 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -19,6 +19,9 @@ #include "Console.hxx" #include "EventHandler.hxx" #include "PKeyboardHandler.hxx" +#include "json.hxx" + +using json = nlohmann::json; #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" @@ -29,6 +32,8 @@ #if defined(BSPF_MACOS) || defined(MACOS_KEYS) static constexpr int MOD3 = KBDM_GUI; +static constexpr int CMD = KBDM_GUI; +static constexpr int OPTION = KBDM_ALT; #else static constexpr int MOD3 = KBDM_ALT; #endif @@ -44,22 +49,42 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler& // Compare if event list version has changed so that key maps became invalid if (version == Event::VERSION) { - string list = myOSystem.settings().getString("keymap_emu"); - myKeyMap.loadMapping(list, EventMode::kCommonMode); - list = myOSystem.settings().getString("keymap_joy"); - myKeyMap.loadMapping(list, EventMode::kJoystickMode); - list = myOSystem.settings().getString("keymap_pad"); - myKeyMap.loadMapping(list, EventMode::kPaddlesMode); - list = myOSystem.settings().getString("keymap_key"); - myKeyMap.loadMapping(list, EventMode::kKeypadMode); - list = myOSystem.settings().getString("keymap_ui"); - myKeyMap.loadMapping(list, EventMode::kMenuMode); + loadSerializedMappings(myOSystem.settings().getString("keymap_emu"), EventMode::kCommonMode); + loadSerializedMappings(myOSystem.settings().getString("keymap_joy"), EventMode::kJoystickMode); + loadSerializedMappings(myOSystem.settings().getString("keymap_pad"), EventMode::kPaddlesMode); + loadSerializedMappings(myOSystem.settings().getString("keymap_key"), EventMode::kKeypadMode); + loadSerializedMappings(myOSystem.settings().getString("keymap_ui"), EventMode::kMenuMode); + updateDefaults = true; } + myKeyMap.enableMod() = myOSystem.settings().getBool("modcombo"); setDefaultMapping(Event::NoType, EventMode::kEmulationMode, updateDefaults); setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults); +#ifdef GUI_SUPPORT + setDefaultMapping(Event::NoType, EventMode::kEditMode, updateDefaults); +#endif // DEBUG +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMapping, EventMode mode) +{ + json mapping; + + try { + mapping = json::parse(serializedMapping); + } catch (json::exception) { + Logger::info("converting legacy keyboard mappings"); + + mapping = KeyMap::convertLegacyMapping(serializedMapping); + } + + try { + myKeyMap.loadMapping(mapping, mode); + } catch (json::exception) { + Logger::error("ignoring bad keyboard mappings"); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -99,6 +124,17 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, // Otherwise, only reset the given event bool eraseAll = !updateDefaults && (event == Event::NoType); +#ifdef GUI_SUPPORT + // Swap Y and Z for QWERTZ keyboards + if(mode == EventMode::kEditMode && myHandler.isQwertz()) + { + if(map.key == KBDK_Z) + map.key = KBDK_Y; + else if(map.key == KBDK_Y) + map.key = KBDK_Z; + } +#endif + if (updateDefaults) { // if there is no existing mapping for the event and @@ -151,13 +187,22 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod setDefaultKey(item, event, EventMode::kMenuMode, updateDefaults); break; + #ifdef GUI_SUPPORT + case EventMode::kEditMode: + // Edit mode events are always set because they are not saved + for(const auto& item: FixedEditMapping) + setDefaultKey(item, event, EventMode::kEditMode); + break; + #endif + default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalKeyboardHandler::defineControllerMappings(const Controller::Type type, Controller::Jack port) +void PhysicalKeyboardHandler::defineControllerMappings( + const Controller::Type type, Controller::Jack port) { // determine controller events to use switch(type) @@ -199,7 +244,8 @@ void PhysicalKeyboardHandler::enableEmulationMappings() myKeyMap.eraseMode(EventMode::kEmulationMode); enableCommonMappings(); - // enable right mode first, so that in case of mapping clashes the left controller has preference + // enable right mode first, so that in case of mapping clashes the left + // controller has preference switch (myRightMode) { case EventMode::kPaddlesMode: @@ -253,14 +299,16 @@ void PhysicalKeyboardHandler::enableCommonMappings() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalKeyboardHandler::enableMappings(const Event::EventSet& events, EventMode mode) +void PhysicalKeyboardHandler::enableMappings(const Event::EventSet& events, + EventMode mode) { for (const auto& event : events) enableMapping(event, mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalKeyboardHandler::enableMapping(const Event::Type event, EventMode mode) +void PhysicalKeyboardHandler::enableMapping(const Event::Type event, + EventMode mode) { // copy from controller mode into emulation mode KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode); @@ -270,7 +318,8 @@ void PhysicalKeyboardHandler::enableMapping(const Event::Type event, EventMode m } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event, const EventMode mode) const +EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event, + const EventMode mode) const { if (mode == EventMode::kEmulationMode) { @@ -328,11 +377,11 @@ void PhysicalKeyboardHandler::eraseMapping(Event::Type event, EventMode mode) void PhysicalKeyboardHandler::saveMapping() { myOSystem.settings().setValue("event_ver", Event::VERSION); - myOSystem.settings().setValue("keymap_emu", myKeyMap.saveMapping(EventMode::kCommonMode)); - myOSystem.settings().setValue("keymap_joy", myKeyMap.saveMapping(EventMode::kJoystickMode)); - myOSystem.settings().setValue("keymap_pad", myKeyMap.saveMapping(EventMode::kPaddlesMode)); - myOSystem.settings().setValue("keymap_key", myKeyMap.saveMapping(EventMode::kKeypadMode)); - myOSystem.settings().setValue("keymap_ui", myKeyMap.saveMapping(EventMode::kMenuMode)); + myOSystem.settings().setValue("keymap_emu", myKeyMap.saveMapping(EventMode::kCommonMode).dump()); + myOSystem.settings().setValue("keymap_joy", myKeyMap.saveMapping(EventMode::kJoystickMode).dump()); + myOSystem.settings().setValue("keymap_pad", myKeyMap.saveMapping(EventMode::kPaddlesMode).dump()); + myOSystem.settings().setValue("keymap_key", myKeyMap.saveMapping(EventMode::kKeypadMode).dump()); + myOSystem.settings().setValue("keymap_ui", myKeyMap.saveMapping(EventMode::kMenuMode).dump()); enableEmulationMappings(); } @@ -356,7 +405,7 @@ bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode, myKeyMap.erase(EventMode::kKeypadMode, key, mod); myKeyMap.erase(EventMode::kCompuMateMode, key, mod); } - else if(evMode != EventMode::kMenuMode) + else if(evMode != EventMode::kMenuMode && evMode != EventMode::kEditMode) { // erase identical mapping for kCommonMode myKeyMap.erase(EventMode::kCommonMode, key, mod); @@ -371,11 +420,12 @@ bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool pressed, bool repeated) +void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, + bool pressed, bool repeated) { #ifdef BSPF_UNIX // Swallow KBDK_TAB under certain conditions - // See commments on 'myAltKeyCounter' for more information + // See comments on 'myAltKeyCounter' for more information if(myAltKeyCounter > 1 && key == KBDK_TAB) { myAltKeyCounter = 0; @@ -431,7 +481,8 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool pre } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommonMapping = { +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::DefaultCommonMapping = { {Event::ConsoleSelect, KBDK_F1}, {Event::ConsoleReset, KBDK_F2}, {Event::ConsoleColor, KBDK_F3}, @@ -470,6 +521,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3}, {Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3}, {Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3}, + {Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL}, {Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3}, {Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3}, {Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL}, @@ -533,8 +585,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleTimeMachine, KBDK_T, MOD3}, #ifdef PNG_SUPPORT - {Event::ToggleContSnapshots, KBDK_S, MOD3}, - {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3}, + {Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL}, + {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL}, #endif {Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL}, @@ -586,12 +638,14 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultMenuMapping = { +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::DefaultMenuMapping = { {Event::UIUp, KBDK_UP}, {Event::UIDown, KBDK_DOWN}, {Event::UILeft, KBDK_LEFT}, {Event::UIRight, KBDK_RIGHT}, {Event::UISelect, KBDK_RETURN}, + {Event::UISelect, KBDK_SPACE}, {Event::UIHome, KBDK_HOME}, {Event::UIEnd, KBDK_END}, @@ -639,6 +693,88 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultMenuM #endif }; +#ifdef GUI_SUPPORT +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::FixedEditMapping = { + {Event::MoveLeftChar, KBDK_LEFT}, + {Event::MoveRightChar, KBDK_RIGHT}, + {Event::SelectLeftChar, KBDK_LEFT, KBDM_SHIFT}, + {Event::SelectRightChar, KBDK_RIGHT, KBDM_SHIFT}, +#if defined(BSPF_MACOS) || defined(MACOS_KEYS) + {Event::MoveLeftWord, KBDK_LEFT, OPTION}, + {Event::MoveRightWord, KBDK_RIGHT, OPTION}, + {Event::MoveHome, KBDK_HOME}, + {Event::MoveHome, KBDK_A, KBDM_CTRL}, + {Event::MoveHome, KBDK_LEFT, CMD}, + {Event::MoveEnd, KBDK_END}, + {Event::MoveEnd, KBDK_E, KBDM_CTRL}, + {Event::MoveEnd, KBDK_RIGHT, CMD}, + {Event::SelectLeftWord, KBDK_LEFT, KBDM_SHIFT | OPTION}, + {Event::SelectRightWord, KBDK_RIGHT, KBDM_SHIFT | OPTION}, + {Event::SelectHome, KBDK_HOME, KBDM_SHIFT}, + {Event::SelectHome, KBDK_LEFT, KBDM_SHIFT | CMD}, + {Event::SelectHome, KBDK_A, KBDM_CTRL | KBDM_SHIFT}, + {Event::SelectEnd, KBDK_E, KBDM_SHIFT | KBDM_CTRL}, + {Event::SelectEnd, KBDK_RIGHT, KBDM_SHIFT | CMD}, + {Event::SelectEnd, KBDK_END, KBDM_SHIFT}, + {Event::SelectAll, KBDK_A, CMD}, + {Event::Delete, KBDK_DELETE}, + {Event::Delete, KBDK_D, KBDM_CTRL}, + {Event::DeleteLeftWord, KBDK_W, KBDM_CTRL}, + {Event::DeleteLeftWord, KBDK_BACKSPACE, OPTION}, + {Event::DeleteRightWord, KBDK_DELETE, OPTION}, + {Event::DeleteHome, KBDK_U, KBDM_CTRL}, + {Event::DeleteHome, KBDK_BACKSPACE, CMD}, + {Event::DeleteEnd, KBDK_K, KBDM_CTRL}, + {Event::Backspace, KBDK_BACKSPACE}, + {Event::Undo, KBDK_Z, CMD}, + {Event::Redo, KBDK_Y, CMD}, + {Event::Redo, KBDK_Z, KBDM_SHIFT | CMD}, + {Event::Cut, KBDK_X, CMD}, + {Event::Copy, KBDK_C, CMD}, + {Event::Paste, KBDK_V, CMD}, +#else + {Event::MoveLeftWord, KBDK_LEFT, KBDM_CTRL}, + {Event::MoveRightWord, KBDK_RIGHT, KBDM_CTRL}, + {Event::MoveHome, KBDK_HOME}, + {Event::MoveEnd, KBDK_END}, + {Event::SelectLeftWord, KBDK_LEFT, KBDM_SHIFT | KBDM_CTRL}, + {Event::SelectRightWord, KBDK_RIGHT, KBDM_SHIFT | KBDM_CTRL}, + {Event::SelectHome, KBDK_HOME, KBDM_SHIFT}, + {Event::SelectEnd, KBDK_END, KBDM_SHIFT}, + {Event::SelectAll, KBDK_A, KBDM_CTRL}, + {Event::Delete, KBDK_DELETE}, + {Event::Delete, KBDK_KP_PERIOD}, + {Event::Delete, KBDK_D, KBDM_CTRL}, + {Event::DeleteLeftWord, KBDK_BACKSPACE, KBDM_CTRL}, + {Event::DeleteLeftWord, KBDK_W, KBDM_CTRL}, + {Event::DeleteRightWord, KBDK_DELETE, KBDM_CTRL}, + {Event::DeleteRightWord, KBDK_D, KBDM_ALT}, + {Event::DeleteHome, KBDK_HOME, KBDM_CTRL}, + {Event::DeleteHome, KBDK_U, KBDM_CTRL}, + {Event::DeleteEnd, KBDK_END, KBDM_CTRL}, + {Event::DeleteEnd, KBDK_K, KBDM_CTRL}, + {Event::Backspace, KBDK_BACKSPACE}, + {Event::Undo, KBDK_Z, KBDM_CTRL}, + {Event::Undo, KBDK_BACKSPACE, KBDM_ALT}, + {Event::Redo, KBDK_Y, KBDM_CTRL}, + {Event::Redo, KBDK_Z, KBDM_SHIFT | KBDM_CTRL}, + {Event::Redo, KBDK_BACKSPACE, KBDM_SHIFT | KBDM_ALT}, + {Event::Cut, KBDK_X, KBDM_CTRL}, + {Event::Cut, KBDK_DELETE, KBDM_SHIFT}, + {Event::Cut, KBDK_KP_PERIOD, KBDM_SHIFT}, + {Event::Copy, KBDK_C, KBDM_CTRL}, + {Event::Copy, KBDK_INSERT, KBDM_CTRL}, + {Event::Paste, KBDK_V, KBDM_CTRL}, + {Event::Paste, KBDK_INSERT, KBDM_SHIFT}, +#endif + {Event::EndEdit, KBDK_RETURN}, + {Event::EndEdit, KBDK_KP_ENTER}, + {Event::AbortEdit, KBDK_ESCAPE}, +}; +#endif + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = { {Event::JoystickZeroUp, KBDK_UP}, @@ -658,6 +794,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoyst {Event::JoystickZeroFire9, KBDK_5}, {Event::JoystickZeroFire9, KBDK_RCTRL}, {Event::JoystickZeroFire9, KBDK_KP_3}, + {Event::JoystickOneUp, KBDK_Y}, {Event::JoystickOneDown, KBDK_H}, {Event::JoystickOneLeft, KBDK_G}, @@ -665,10 +802,27 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoyst {Event::JoystickOneFire, KBDK_F}, {Event::JoystickOneFire5, KBDK_6}, {Event::JoystickOneFire9, KBDK_7}, + + {Event::JoystickTwoUp, KBDK_UP, KBDM_SHIFT}, + {Event::JoystickTwoDown, KBDK_DOWN, KBDM_SHIFT}, + {Event::JoystickTwoLeft, KBDK_LEFT, KBDM_SHIFT}, + {Event::JoystickTwoRight, KBDK_RIGHT, KBDM_SHIFT}, + {Event::JoystickTwoUp, KBDK_KP_8, KBDM_SHIFT}, + {Event::JoystickTwoDown, KBDK_KP_2, KBDM_SHIFT}, + {Event::JoystickTwoLeft, KBDK_KP_4, KBDM_SHIFT}, + {Event::JoystickTwoRight, KBDK_KP_6, KBDM_SHIFT}, + {Event::JoystickTwoFire, KBDK_SPACE, KBDM_SHIFT}, + + {Event::JoystickThreeUp, KBDK_Y, KBDM_SHIFT}, + {Event::JoystickThreeDown, KBDK_H, KBDM_SHIFT}, + {Event::JoystickThreeLeft, KBDK_G, KBDM_SHIFT}, + {Event::JoystickThreeRight, KBDK_J, KBDM_SHIFT}, + {Event::JoystickThreeFire, KBDK_F, KBDM_SHIFT}, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultPaddleMapping = { +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::DefaultPaddleMapping = { {Event::PaddleZeroDecrease, KBDK_RIGHT}, {Event::PaddleZeroIncrease, KBDK_LEFT}, {Event::PaddleZeroFire, KBDK_SPACE}, @@ -690,7 +844,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultPaddl }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultKeypadMapping = { +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::DefaultKeypadMapping = { {Event::KeyboardZero1, KBDK_1}, {Event::KeyboardZero2, KBDK_2}, {Event::KeyboardZero3, KBDK_3}, @@ -719,7 +874,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultKeypa }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::CompuMateMapping = { +PhysicalKeyboardHandler::EventMappingArray +PhysicalKeyboardHandler::CompuMateMapping = { {Event::CompuMateShift, KBDK_LSHIFT}, {Event::CompuMateShift, KBDK_RSHIFT}, {Event::CompuMateFunc, KBDK_LCTRL}, diff --git a/src/common/PKeyboardHandler.hxx b/src/common/PKeyboardHandler.hxx index ede6aa55a..b285f619b 100644 --- a/src/common/PKeyboardHandler.hxx +++ b/src/common/PKeyboardHandler.hxx @@ -45,6 +45,8 @@ class PhysicalKeyboardHandler PhysicalKeyboardHandler(OSystem& system, EventHandler& handler); + void loadSerializedMappings(const string& serializedMappings, EventMode mode); + void setDefaultMapping(Event::Type type, EventMode mode, bool updateDefaults = false); /** define mappings for current controllers */ @@ -106,6 +108,7 @@ class PhysicalKeyboardHandler void enableMappings(const Event::EventSet& events, EventMode mode); void enableMapping(const Event::Type event, EventMode mode); + private: OSystem& myOSystem; EventHandler& myHandler; @@ -132,6 +135,9 @@ class PhysicalKeyboardHandler // Controller menu and common emulation mappings static EventMappingArray DefaultMenuMapping; + #ifdef GUI_SUPPORT + static EventMappingArray FixedEditMapping; + #endif static EventMappingArray DefaultCommonMapping; // Controller specific mappings static EventMappingArray DefaultJoystickMapping; diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index ae7d3390f..2a6f84d6a 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -267,7 +267,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame) buf << "Enabling snapshots in " << interval << " second intervals"; interval *= uInt32(myOSystem.frameRate()); } - myOSystem.frameBuffer().showMessage(buf.str()); + myOSystem.frameBuffer().showTextMessage(buf.str()); setContinuousSnapInterval(interval); } else @@ -276,7 +276,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame) buf << "Disabling snapshots, generated " << (mySnapCounter / mySnapInterval) << " files"; - myOSystem.frameBuffer().showMessage(buf.str()); + myOSystem.frameBuffer().showTextMessage(buf.str()); setContinuousSnapInterval(0); } } @@ -296,7 +296,6 @@ void PNGLibrary::takeSnapshot(uInt32 number) // Figure out the correct snapshot name string filename; - bool showmessage = number == 0; string sspath = myOSystem.snapshotSaveDir().getPath() + (myOSystem.settings().getString("snapname") != "int" ? myOSystem.romFile().getNameWithExt("") @@ -347,9 +346,9 @@ void PNGLibrary::takeSnapshot(uInt32 number) VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo()); // Now create a PNG snapshot + string message = "Snapshot saved"; if(myOSystem.settings().getBool("ss1x")) { - string message = "Snapshot saved"; try { Common::Rect rect; @@ -360,8 +359,6 @@ void PNGLibrary::takeSnapshot(uInt32 number) { message = e.what(); } - if(showmessage) - myOSystem.frameBuffer().showMessage(message); } else { @@ -369,7 +366,6 @@ void PNGLibrary::takeSnapshot(uInt32 number) myOSystem.frameBuffer().enableMessages(false); myOSystem.frameBuffer().tiaSurface().renderForSnapshot(); - string message = "Snapshot saved"; try { myOSystem.png().saveImage(filename, comments); @@ -381,9 +377,8 @@ void PNGLibrary::takeSnapshot(uInt32 number) // Re-enable old messages myOSystem.frameBuffer().enableMessages(true); - if(showmessage) - myOSystem.frameBuffer().showMessage(message); } + myOSystem.frameBuffer().showTextMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 030ff4d9e..f13c18ab1 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -69,35 +69,69 @@ void PaletteHandler::cyclePalette(int direction) const string palette = toPaletteName(PaletteType(type)); const string message = MESSAGES[type] + " palette"; - myOSystem.frameBuffer().showMessage(message); + myOSystem.frameBuffer().showTextMessage(message); setPalette(palette); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PaletteHandler::isCustomAdjustable() const +{ + return myCurrentAdjustable >= CUSTOM_START + && myCurrentAdjustable <= CUSTOM_END; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PaletteHandler::isPhaseShift() const +{ + return myCurrentAdjustable == PHASE_SHIFT; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PaletteHandler::isRGBScale() const +{ + return myCurrentAdjustable >= RED_SCALE && myCurrentAdjustable <= BLUE_SCALE; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PaletteHandler::isRGBShift() const +{ + return myCurrentAdjustable >= RED_SHIFT && myCurrentAdjustable <= BLUE_SHIFT; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::showAdjustableMessage() { - const bool isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; ostringstream msg, buf; msg << "Palette " << myAdjustables[myCurrentAdjustable].name; - if(isPhaseShift) + if(isPhaseShift()) { const ConsoleTiming timing = myOSystem.console().timing(); const bool isNTSC = timing == ConsoleTiming::ntsc; const float value = myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC; buf << std::fixed << std::setprecision(1) << value << DEGREE; - myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().showGaugeMessage( "Palette phase shift", buf.str(), value, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_PHASE_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_PHASE_SHIFT); + } + else if(isRGBShift()) + { + const float value = *myAdjustables[myCurrentAdjustable].value; + + buf << std::fixed << std::setprecision(1) << value << DEGREE; + myOSystem.frameBuffer().showGaugeMessage( + msg.str(), buf.str(), value, -MAX_RGB_SHIFT, +MAX_RGB_SHIFT); } else { - const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value); + const int value = isRGBScale() + ? scaleRGBTo100(*myAdjustables[myCurrentAdjustable].value) + : scaleTo100(*myAdjustables[myCurrentAdjustable].value); buf << value << "%"; - myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().showGaugeMessage( msg.str(), buf.str(), value); } } @@ -106,15 +140,15 @@ void PaletteHandler::showAdjustableMessage() void PaletteHandler::cycleAdjustable(int direction) { const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); - bool isPhaseShift; + bool isCustomAdj; do { myCurrentAdjustable = BSPF::clampw(int(myCurrentAdjustable + direction), 0, NUM_ADJUSTABLES - 1); - isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; + isCustomAdj = isCustomAdjustable(); // skip phase shift when 'Custom' palette is not selected - if(!direction && isPhaseShift && !isCustomPalette) + if(!direction && isCustomAdj && !isCustomPalette) myCurrentAdjustable++; - } while(isPhaseShift && !isCustomPalette); + } while(isCustomAdj && !isCustomPalette); showAdjustableMessage(); } @@ -122,29 +156,38 @@ void PaletteHandler::cycleAdjustable(int direction) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeAdjustable(int adjustable, int direction) { - const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); - const bool isPhaseShift = myAdjustables[adjustable].value == nullptr; - myCurrentAdjustable = adjustable; - if(isPhaseShift && !isCustomPalette) - myCurrentAdjustable++; - changeCurrentAdjustable(direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeCurrentAdjustable(int direction) { - if(myAdjustables[myCurrentAdjustable].value == nullptr) + if(isPhaseShift()) changeColorPhaseShift(direction); else { - int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); + if(isRGBScale()) + { + int newVal = scaleRGBTo100(*myAdjustables[myCurrentAdjustable].value); - newVal = BSPF::clamp(newVal + direction * 1, 0, 100); + newVal = BSPF::clamp(newVal + direction * 1, 0, 100); + *myAdjustables[myCurrentAdjustable].value = scaleRGBFrom100(newVal); + } + else if(isRGBShift()) + { + float newShift = *myAdjustables[myCurrentAdjustable].value; - *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); + newShift = BSPF::clamp(newShift + direction * 0.5F, -MAX_RGB_SHIFT, MAX_RGB_SHIFT); + *myAdjustables[myCurrentAdjustable].value = newShift; + } + else + { + int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); + newVal = BSPF::clamp(newVal + direction * 1, 0, 100); + *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); + } showAdjustableMessage(); setPalette(); } @@ -162,7 +205,7 @@ void PaletteHandler::changeColorPhaseShift(int direction) const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL; - newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_SHIFT, shift + MAX_SHIFT); + newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_PHASE_SHIFT, shift + MAX_PHASE_SHIFT); if(isNTSC) myPhaseNTSC = newPhase; @@ -181,15 +224,21 @@ void PaletteHandler::loadConfig(const Settings& settings) { // Load adjustables myPhaseNTSC = BSPF::clamp(settings.getFloat("pal.phase_ntsc"), - DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT); + DEF_NTSC_SHIFT - MAX_PHASE_SHIFT, DEF_NTSC_SHIFT + MAX_PHASE_SHIFT); myPhasePAL = BSPF::clamp(settings.getFloat("pal.phase_pal"), - DEF_PAL_SHIFT - MAX_SHIFT, DEF_PAL_SHIFT + MAX_SHIFT); + DEF_PAL_SHIFT - MAX_PHASE_SHIFT, DEF_PAL_SHIFT + MAX_PHASE_SHIFT); + myRedScale = BSPF::clamp(settings.getFloat("pal.red_scale"), -1.0F, 1.0F) + 1.F; + myGreenScale = BSPF::clamp(settings.getFloat("pal.green_scale"), -1.0F, 1.0F) + 1.F; + myBlueScale = BSPF::clamp(settings.getFloat("pal.blue_scale"), -1.0F, 1.0F) + 1.F; + myRedShift = BSPF::clamp(settings.getFloat("pal.red_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT); + myGreenShift = BSPF::clamp(settings.getFloat("pal.green_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT); + myBlueShift = BSPF::clamp(settings.getFloat("pal.blue_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT); - myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F); - mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F); - myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F); - myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F); - myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F); + myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F); + mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F); + myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F); + myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F); + myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -198,6 +247,12 @@ void PaletteHandler::saveConfig(Settings& settings) const // Save adjustables settings.setValue("pal.phase_ntsc", myPhaseNTSC); settings.setValue("pal.phase_pal", myPhasePAL); + settings.setValue("pal.red_scale", myRedScale - 1.F); + settings.setValue("pal.green_scale", myGreenScale - 1.F); + settings.setValue("pal.blue_scale", myBlueScale - 1.F); + settings.setValue("pal.red_shift", myRedShift); + settings.setValue("pal.green_shift", myGreenShift); + settings.setValue("pal.blue_shift", myBlueShift); settings.setValue("pal.hue", myHue); settings.setValue("pal.saturation", mySaturation); @@ -209,8 +264,14 @@ void PaletteHandler::saveConfig(Settings& settings) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::setAdjustables(const Adjustable& adjustable) { - myPhaseNTSC = adjustable.phaseNtsc / 10.F; - myPhasePAL = adjustable.phasePal / 10.F; + myPhaseNTSC = scaleFromAngles(adjustable.phaseNtsc); + myPhasePAL = scaleFromAngles(adjustable.phasePal); + myRedScale = scaleRGBFrom100(adjustable.redScale); + myGreenScale = scaleRGBFrom100(adjustable.greenScale); + myBlueScale = scaleRGBFrom100(adjustable.blueScale); + myRedShift = scaleFromAngles(adjustable.redShift); + myGreenShift = scaleFromAngles(adjustable.greenShift); + myBlueShift = scaleFromAngles(adjustable.blueShift); myHue = scaleFrom100(adjustable.hue); mySaturation = scaleFrom100(adjustable.saturation); @@ -222,8 +283,14 @@ void PaletteHandler::setAdjustables(const Adjustable& adjustable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::getAdjustables(Adjustable& adjustable) const { - adjustable.phaseNtsc = myPhaseNTSC * 10.F; - adjustable.phasePal = myPhasePAL * 10.F; + adjustable.phaseNtsc = scaleToAngles(myPhaseNTSC); + adjustable.phasePal = scaleToAngles(myPhasePAL); + adjustable.redScale = scaleRGBTo100(myRedScale); + adjustable.greenScale = scaleRGBTo100(myGreenScale); + adjustable.blueScale = scaleRGBTo100(myBlueScale); + adjustable.redShift = scaleToAngles(myRedShift); + adjustable.greenShift = scaleToAngles(myGreenShift); + adjustable.blueShift = scaleToAngles(myBlueShift); adjustable.hue = scaleTo100(myHue); adjustable.saturation = scaleTo100(mySaturation); @@ -371,10 +438,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) constexpr int NUM_LUMA = 8; constexpr float SATURATION = 0.25F; // default saturation - float color[NUM_CHROMA][2] = {{0.0F}}; - if(timing == ConsoleTiming::ntsc) { + vector2d IQ[NUM_CHROMA]; // YIQ is YUV shifted by 33° constexpr float offset = 33 * BSPF::PI_f / 180; const float shift = myPhaseNTSC * BSPF::PI_f / 180; @@ -382,22 +448,23 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) { - color[chroma][0] = SATURATION * sinf(offset + shift * (chroma - 1)); - color[chroma][1] = SATURATION * cosf(offset + shift * (chroma - 1) - BSPF::PI_f); + IQ[chroma] = vector2d(SATURATION * sinf(offset + shift * (chroma - 1)), + SATURATION * cosf(offset + shift * (chroma - 1) - BSPF::PI_f)); } + const vector2d IQR = scale(rotate(vector2d(+0.956F, +0.621F), myRedShift), myRedScale); + const vector2d IQG = scale(rotate(vector2d(-0.272F, -0.647F), myGreenShift), myGreenScale); + const vector2d IQB = scale(rotate(vector2d(-1.106F, +1.703F), myBlueShift), myBlueScale); for(int chroma = 0; chroma < NUM_CHROMA; chroma++) { - const float I = color[chroma][0]; - const float Q = color[chroma][1]; - for(int luma = 0; luma < NUM_LUMA; luma++) { const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - float R = Y + 0.956F * I + 0.621F * Q; - float G = Y - 0.272F * I - 0.647F * Q; - float B = Y - 1.106F * I + 1.703F * Q; + float R = Y + dotProduct(IQ[chroma], IQR); + float G = Y + dotProduct(IQ[chroma], IQG); + float B = Y + dotProduct(IQ[chroma], IQB); + if(R < 0) R = 0; if(G < 0) G = 0; @@ -420,35 +487,37 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) constexpr float offset = BSPF::PI_f; const float shift = myPhasePAL * BSPF::PI_f / 180; constexpr float fixedShift = 22.5F * BSPF::PI_f / 180; + vector2d UV[NUM_CHROMA]; // colors 0, 1, 14 and 15 are grayscale for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) { int idx = NUM_CHROMA - 1 - chroma; - color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma); + + UV[idx].x = SATURATION * sinf(offset - fixedShift * chroma); if ((idx & 1) == 0) - color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); + UV[idx].y = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); else - color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); + UV[idx].y = SATURATION * -sinf(offset - shift * chroma / 2.F); } + // Most sources + const vector2d UVR = scale(rotate(vector2d( 0.000F, +1.403F), myRedShift), myRedScale); + const vector2d UVG = scale(rotate(vector2d(-0.344F, -0.714F), myGreenShift), myGreenScale); + const vector2d UVB = scale(rotate(vector2d(+0.714F, 0.000F), myBlueShift), myBlueScale); + // German Wikipedia, huh??? + //float R = Y + 1 / 0.877 * V; + //float B = Y + 1 / 0.493 * U; + //float G = 1.704 * Y - 0.590 * R - 0.194 * B; for(int chroma = 0; chroma < NUM_CHROMA; chroma++) { - const float U = color[chroma][0]; - const float V = color[chroma][1]; - for(int luma = 0; luma < NUM_LUMA; luma++) { const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - // Most sources - float R = Y + 1.403F * V; - float G = Y - 0.344F * U - 0.714F * V; - float B = Y + 1.770F * U; - // German Wikipedia, huh??? - //float B = Y + 1 / 0.493 * U; - //float R = Y + 1 / 0.877 * V; - //float G = 1.704 * Y - 0.590 * R - 0.194 * B; + float R = Y + dotProduct(UV[chroma], UVR); + float G = Y + dotProduct(UV[chroma], UVG); + float B = Y + dotProduct(UV[chroma], UVB); if(R < 0) R = 0.0; if(G < 0) G = 0.0; @@ -491,6 +560,28 @@ void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float B = BSPF::clamp(b, 0.F, 255.F); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteHandler::vector2d PaletteHandler::rotate(const PaletteHandler::vector2d& vec, float angle) const +{ + const float r = angle * BSPF::PI_f / 180; + + return PaletteHandler::vector2d(vec.x * cosf(r) - vec.y * sinf(r), + vec.x * sinf(r) + vec.y * cosf(r)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteHandler::vector2d PaletteHandler::scale(const PaletteHandler::vector2d& vec, float factor) const +{ + return PaletteHandler::vector2d(vec.x * factor, vec.y * factor); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float PaletteHandler::dotProduct(const PaletteHandler::vector2d& vec1, + const PaletteHandler::vector2d& vec2) const +{ + return vec1.x * vec2.x + vec1.y * vec2.y; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const PaletteArray PaletteHandler::ourNTSCPalette = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 956fcf9b3..42ba37cfc 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -35,20 +35,32 @@ class PaletteHandler // Phase shift default and limits static constexpr float DEF_NTSC_SHIFT = 26.2F; static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5 - static constexpr float MAX_SHIFT = 4.5F; + static constexpr float MAX_PHASE_SHIFT = 4.5F; + static constexpr float DEF_RGB_SHIFT = 0.0F; + static constexpr float MAX_RGB_SHIFT = 22.5F; enum Adjustables { PHASE_SHIFT, + RED_SCALE, + GREEN_SCALE, + BLUE_SCALE, + RED_SHIFT, + GREEN_SHIFT, + BLUE_SHIFT, HUE, SATURATION, CONTRAST, BRIGHTNESS, - GAMMA + GAMMA, + CUSTOM_START = PHASE_SHIFT, + CUSTOM_END = BLUE_SHIFT, }; // Externally used adjustment parameters struct Adjustable { - float phaseNtsc{0.F}, phasePal{0.F}; + float phaseNtsc{0.F}, phasePal{0.F}, + redScale{0.F}, greenScale{0.F}, blueScale{0.F}, + redShift{0.F}, greenShift{0.F}, blueShift{0.F}; uInt32 hue{0}, saturation{0}, contrast{0}, brightness{0}, gamma{0}; }; @@ -108,6 +120,7 @@ class PaletteHandler */ void setPalette(); + private: static constexpr char DEGREE = 0x1c; @@ -121,12 +134,43 @@ class PaletteHandler MaxType = Custom }; + struct vector2d { + float x{0.F}; + float y{0.F}; + + explicit vector2d(float _x = 0.F, float _y = 0.F) + : x(_x), y(_y) { } + }; + + /** + Convert RGB adjustables from/to 100% scale + */ + static constexpr float scaleRGBFrom100(float x) { return x / 50.F; } + static constexpr uInt32 scaleRGBTo100(float x) { return uInt32(50.0001F * (x - 0.F)); } + + /** + Convert angles + */ + static constexpr float scaleFromAngles(float x) { return x / 10.F; } + static constexpr Int32 scaleToAngles(float x) { return uInt32(10.F * x); } + /** Convert adjustables from/to 100% scale */ static constexpr float scaleFrom100(float x) { return (x / 50.F) - 1.F; } static constexpr uInt32 scaleTo100(float x) { return uInt32(50.0001F * (x + 1.F)); } + /** + Check for 'Custom' palette only adjustables + */ + bool isCustomAdjustable() const; + + bool isPhaseShift() const; + + bool isRGBScale() const; + + bool isRGBShift() const; + /** Convert palette settings name to enumeration. @@ -186,6 +230,21 @@ class PaletteHandler */ void adjustHueSaturation(int& R, int& G, int& B, float H, float S); + /** + Rotate a 2D vector. + */ + vector2d rotate(const vector2d& vec, float angle) const; + + /** + Scale a 2D vector. + */ + vector2d scale(const vector2d& vec, float factor) const; + + /** + Get the dot product of two 2D vectors. + */ + float dotProduct(const vector2d& vec1, const vector2d& vec2) const; + /** Loads a user-defined palette file (from OSystem::paletteFile), filling the appropriate user-defined palette arrays. @@ -193,7 +252,7 @@ class PaletteHandler void loadUserPalette(); private: - static constexpr int NUM_ADJUSTABLES = 6; + static constexpr int NUM_ADJUSTABLES = 12; OSystem& myOSystem; @@ -207,6 +266,12 @@ class PaletteHandler const std::array myAdjustables = { { { "phase shift", nullptr }, + { "red scale", &myRedScale }, + { "green scale", &myGreenScale }, + { "blue scale", &myBlueScale }, + { "red shift", &myRedShift }, + { "green shift", &myGreenShift }, + { "blue shift", &myBlueShift }, { "hue", &myHue }, { "saturation", &mySaturation }, { "contrast", &myContrast }, @@ -217,6 +282,14 @@ class PaletteHandler // NTSC and PAL color phase shifts float myPhaseNTSC{DEF_NTSC_SHIFT}; float myPhasePAL{DEF_PAL_SHIFT}; + // Color intensities + float myRedScale{1.0F}; + float myGreenScale{1.0F}; + float myBlueScale{1.0F}; + // Color shifts + float myRedShift{0.0F}; + float myGreenShift{0.0F}; + float myBlueShift{0.0F}; // range -1.0 to +1.0 (as in AtariNTSC) // Basic parameters float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees diff --git a/src/common/PhysicalJoystick.cxx b/src/common/PhysicalJoystick.cxx index b784c45ae..488d1f318 100644 --- a/src/common/PhysicalJoystick.cxx +++ b/src/common/PhysicalJoystick.cxx @@ -22,6 +22,24 @@ #include "Vec.hxx" #include "bspf.hxx" #include "PhysicalJoystick.hxx" +#include "jsonDefinitions.hxx" +#include "Logger.hxx" + +using json = nlohmann::json; + +namespace { + string jsonName(EventMode eventMode) { + return json(eventMode).get(); + } + + EventMode eventModeFromJsonName(const string& name) { + EventMode result; + + from_json(json(name), result); + + return result; + } +} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PhysicalJoystick::initialize(int index, const string& desc, @@ -45,30 +63,56 @@ void PhysicalJoystick::initialize(int index, const string& desc, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string PhysicalJoystick::getMap() const +json PhysicalJoystick::getMap() const { - // The mapping structure (for remappable devices) is defined as follows: - // '>'['|'(':'
      Cart.Name Indicates the actual name of the game. When you save snapshots, load/save state files, or use the ROM Audit Mode functionality, this is the name that will be used for the respective file(s).
      Cart.MD5:Cart.MD5 Indicates the MD5 checksum of the ROM image as a string of hexadecimal digits. Stella uses this property while attempting to match a game with its block of properties. If the @@ -4302,22 +4627,22 @@ Ms Pac-Man (Stella extended codes):
      Cart.Manufacturer:Cart.Manufacturer Indicates the game's manufacturer.
      Cart.ModelNo:Cart.ModelNo Indicates the manufacturer's model number for the game.
      Cart.Rarity:Cart.Rarity Indicates how rare a cartridge is, based on the scale described on AtariAge.
      Cart.Note:Cart.Note Contains any special notes about playing the game.