Merge branch 'master' into feature-highscores

This commit is contained in:
thrust26 2020-11-28 20:10:17 +01:00
commit c116ed8d25
480 changed files with 14152 additions and 8525 deletions

1
.gitignore vendored
View File

@ -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/*

68
.gitlab-ci.yml Normal file
View File

@ -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

View File

@ -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

View File

@ -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.
@ -33,16 +87,42 @@
Basically, you are now able to put many files that Stella uses inside
one ZIP file, and distribute just that file.
* Extended AtariVox support to handle flow control, so that long phrases
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.
* 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)
* Fixed a bug in initial controller mapping.
6.2 to 6.2.1: (June 20, 2020)

View File

@ -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
@ -80,6 +80,11 @@ else
endif
endif
ifdef RELEASE
CXXFLAGS += -flto -fno-rtti
LDFLAGS += -flto -fno-rtti
endif
#######################################################################
# Misc stuff - you should never have to edit this #
#######################################################################

16
configure vendored
View File

@ -26,6 +26,7 @@ _build_sqlite=no
_build_static=no
_build_profile=no
_build_debug=no
_build_release=no
# more defaults
_ranlib=ranlib
@ -261,8 +262,10 @@ for ac_option in $@; do
--disable-static) _build_static=no ;;
--enable-profile) _build_profile=yes ;;
--disable-profile) _build_profile=no ;;
--enable-debug) _build_debug=yes ;;
--disable-debug) _build_debug=false ;;
--enable-debug) _build_debug=yes ;;
--disable-debug) _build_debug=no ;;
--enable-release) _build_release=yes ;;
--disable-release) _build_release=no ;;
--with-sdl-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
_sdlpath="$arg:$arg/bin"
@ -277,7 +280,7 @@ for ac_option in $@; do
ZLIB_CFLAGS="-I$_prefix/include"
ZLIB_LIBS="-L$_prefix/lib"
;;
--with-sqlite-prefix=*)
--with-sqlite-prefix=*)
_prefix=`echo $ac_option | cut -d '=' -f 2`
SQLITE_CFLAGS="-I$_prefix/include"
SQLITE_LIBS="-L$_prefix/lib"
@ -382,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
@ -925,6 +928,10 @@ if test "$_build_debug" = no ; then
_build_debug=
fi
if test "$_build_release" = no ; then
_build_release=
fi
echo "Creating config.mak"
cat > config.mak << EOF
# -------- Generated by configure -----------
@ -958,6 +965,7 @@ DOCDIR := $_docdir
DATADIR := $_datadir
PROFILE := $_build_profile
DEBUG := $_build_debug
RELEASE := $_build_release
$_make_def_HAVE_GCC
$_make_def_HAVE_CLANG

14
debian/changelog vendored
View File

@ -1,3 +1,17 @@
stella (6.4) stable; urgency=high
* Version 6.4 release
-- Stephen Anthony <sa666666@gmail.com> Mon, 2 Nov 2020 17:09:59 -0230
stella (6.3-1) stable; urgency=high
* Version 6.3 release
-- Stephen Anthony <sa666666@gmail.com> Wed, 7 Oct 2020 17:09:59 -0230
stella (6.2.1-1) stable; urgency=high
* Version 6.2.1 release

2
debian/compat vendored
View File

@ -1 +1 @@
9
10

42
debian/control vendored
View File

@ -1,17 +1,39 @@
Source: stella
Section: games
Priority: optional
Maintainer: Stephen Anthony <sa666666@gmail.com>
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.

216
debian/copyright vendored
View File

@ -1,29 +1,205 @@
This package was debianized first by Tom Lear <tom@ticking.accesscom.com> 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 <https://stella-emu.github.io>
Files: *
Copyright: 1995-2020 Bradford W. Mott, Stephen Anthony and the Stella
Team
License: GPL-2+
Copyright Holder(s): Bradford W. Mott <bwmott@acm.org> and the Stella Team
Files: debian/*
Copyright: 1998-2004 Tom Lear <tom@trap.mtview.ca.us>
2006 Mario Iseli <admin@marioiseli.com>
2010-2020 Stephen Kitt <skitt@debian.org>
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 <bwmott@acm.org>
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'.

1
debian/dirs vendored
View File

@ -1 +0,0 @@
usr/bin

9
debian/doc-base vendored Normal file
View File

@ -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

77
debian/rules vendored
View File

@ -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
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

6
debian/watch vendored
View File

@ -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

View File

@ -15,7 +15,7 @@
<body>
<center><b><font size="7">Stella</font></b></center>
<center><h4><b>Release 6.2.1</b></h4></center>
<center><h4><b>Release 6.4</b></h4></center>
<center><h1><b>Integrated Debugger</b></h1></center>
<center><h4><b>(a work in progress)</b></h4></center>
<br>
@ -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).</p>
<p>Note for the GUI display:
<ul>
<li>Hexadecimal values are either not prefixed or with '$'.</li>
<li>Decimal values are prefixed with '#'.</li>
<li>Binary values are prefixed with '%'.</li>
</ul>
</p>
<p>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).</p>
<tr><td> _cycleslo</td><td> Lower 32 bits of number of cycles since emulation started</td></tr>
<tr><td> _fcount</td><td> Number of frames since emulation started</td></tr>
<tr><td> _fcycles</td><td> Number of cycles since frame started</td></tr>
<tr><td> _ftimreadcycles</td><td>Number of cycles used by timer reads since frame started</td></tr>
<tr><td> _fwsynccycles</td><td>Number of cycles skipped by WSYNC since frame started</td></tr>
<tr><td> _icycles</td><td> Number of cycles of last instruction</td></tr>
<tr><td> _scan</td><td> Current scanline count</td></tr>
<tr><td> _scanend</td><td> Scanline count at end of last frame</td></tr>
<tr><td> _scycles</td><td> Number of cycles in current scanline</td></tr>
<tr><td> _timwrapread</td><td> Timer read wrapped on this cycle</td></tr>
<tr><td> _timwrapwrite</td><td> Timer write wrapped on this cycle</td></tr>
<tr><td> _vblank</td><td> Whether vertical blank is enabled (1 or 0)</td></tr>
<tr><td> _vsync</td><td> Whether vertical sync is enabled (1 or 0)</td></tr>
</table>
@ -1131,16 +1143,20 @@ as illustrated:</p>
<!-- ///////////////////////////////////////////////////////////////////////// -->
<br>
<h2><a name="TIAInfo"><u>(F)</u> TIA Information</a></h2>
<p>To the right of the <a href="#TIADisplay"><b>TIA Display</b></a> area, TIA information is displayed:</p>
<p>To the right of the <a href="#TIADisplay"><b>TIA Display</b></a> area, TIA information is displayed (all values are decimal):</p>
<p><img src="graphics/debugger_tiainfo.png"></p>
<p>The indicators are as follows (note that all these are read-only):</p>
<ul>
<li><b>Frame Count</b>: The number of frames since this ROM was loaded or reset.</li>
<li><b>Frame Cycle</b>: The number of CPU cycles that have been executed this frame since
<li><b>Frame Cycls</b>: The number of CPU cycles that have been executed this frame since
VSYNC was cleared at scanline 0.</li>
<li><b>WSync Cycls</b>: The number of CPU cycles that have been skipped by WSYNC this frame since
VSYNC was cleared at scanline 0.</li>
<li><b>Timer Cycls</b>: The number of CPU cycles (approximately) that have been used by timer read loops since
VSYNC was cleared at scanline 0.</li>
<li><b>Total</b>: The total number of CPU cycles since this ROM was loaded or reset.</li>
<li><b>Delta</b>: The number of CPU cycles that have been executed since the last debugger
interrupt.</li>
<li><b>Frame Cnt.</b>: The number of frames since this ROM was loaded or reset.</li>
<li><b>Scanline</b>: 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).</li>
@ -1273,10 +1289,9 @@ are lost (they will NOT end up in the Carry flag).</p>
<p>This is a spreadsheet-like GUI for inspecting and changing the contents
of the 2600's zero-page RAM.</p>
<p>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
<a href="#DataOpButtons"><b>Data Operations Buttons</b></a> or the associated
shortcut keys.</p>
@ -1287,7 +1302,8 @@ more comprehensive. It will undo <b>all</b> operations on <b>all</b> cells
since you first made a change.</p>
<p>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.</p>
and the other three textboxes show the hex, decimal and binary equivalent value.
The values can be edited here too.</p>
<p>The remaining buttons to the right are further explained in the next section.</p>
@ -1569,7 +1585,7 @@ Go ahead and try to change something!</p>
<p>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:</p>
<p><img src="graphics/debugger_ram-f8sc.png"></p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,7 @@
<center><h1>Stella for RetroN 77</h1></center>
<center><h2>Atari 2600 VCS emulator</h2></center>
<center>Release 6.2.1</center>
<center>Release 6.4</center>
<center><h2>Quick Navigation Guide</h2></center>
<br/>

View File

@ -24,7 +24,7 @@ class BankRomCheat : public Cheat
{
public:
BankRomCheat(OSystem& os, const string& name, const string& code);
virtual ~BankRomCheat() = default;
~BankRomCheat() override = default;
bool enable() override;
bool disable() override;

View File

@ -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);

View File

@ -36,7 +36,7 @@ class CheatCodeDialog : public Dialog
public:
CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font);
virtual ~CheatCodeDialog();
~CheatCodeDialog() override;
protected:
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;

View File

@ -24,7 +24,7 @@ class CheetahCheat : public Cheat
{
public:
CheetahCheat(OSystem& os, const string& name, const string& code);
virtual ~CheetahCheat() = default;
~CheetahCheat() override = default;
bool enable() override;
bool disable() override;

View File

@ -24,7 +24,7 @@ class RamCheat : public Cheat
{
public:
RamCheat(OSystem& os, const string& name, const string& code);
virtual ~RamCheat() = default;
~RamCheat() override = default;
bool enable() override;
bool disable() override;

View File

@ -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()
{
@ -220,7 +248,6 @@ void EventHandlerSDL2::pollEvent()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
: myStick(nullptr)
{
ASSERT_MAIN_THREAD;

View File

@ -36,7 +36,7 @@ class EventHandlerSDL2 : public EventHandler
Create a new SDL2 event handler object
*/
explicit EventHandlerSDL2(OSystem& osystem);
virtual ~EventHandlerSDL2();
~EventHandlerSDL2() override;
private:
/**
@ -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.
*/
@ -61,7 +67,7 @@ class EventHandlerSDL2 : public EventHandler
virtual ~JoystickSDL2();
private:
SDL_Joystick* myStick;
SDL_Joystick* myStick{nullptr};
};
private:

View File

@ -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<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
{
ASSERT_MAIN_THREAD;
@ -105,7 +99,7 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& 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<Common::Size>& 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<FBSurface> FrameBufferSDL2::createSurface(
unique_ptr<FBSurface> FBBackendSDL2::createSurface(
uInt32 w,
uInt32 h,
FrameBuffer::ScalingInterpolation interpolation,
ScalingInterpolation inter,
const uInt32* data
) const
{
return make_unique<FBSurfaceSDL2>(const_cast<FrameBufferSDL2&>(*this), w, h, interpolation, data);
return make_unique<FBSurfaceSDL2>
(const_cast<FBBackendSDL2&>(*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);
}

View File

@ -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);
virtual ~FrameBufferSDL2();
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<FBSurface>
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

View File

@ -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<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
{
setSrcPosInternal(x, y);
if(setSrcPosInternal(x, y))
reinitializeBlitter();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h)
{
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(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<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
{
setDstPosInternal(x, y);
if(setDstPosInternal(x, y))
reinitializeBlitter();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h)
{
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(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;

View File

@ -20,7 +20,7 @@
#include "bspf.hxx"
#include "FBSurface.hxx"
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "sdl_blitter/Blitter.hxx"
/**
@ -32,10 +32,9 @@
class FBSurfaceSDL2 : public FBSurface
{
public:
FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height,
FrameBuffer::ScalingInterpolation interpolation,
const uInt32* staticData);
virtual ~FBSurfaceSDL2();
FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height,
ScalingInterpolation inter, const uInt32* staticData);
~FBSurfaceSDL2() override;
// Most of the surface drawing primitives are implemented in FBSurface;
// the ones implemented here use SDL-specific code for extra performance
@ -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<uInt32>(mySrcR.x) || y != static_cast<uInt32>(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<uInt32>(mySrcR.w) || h != static_cast<uInt32>(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<uInt32>(myDstR.x) || y != static_cast<uInt32>(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<uInt32>(myDstR.w) || h != static_cast<uInt32>(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<Blitter> 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};

View File

@ -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<FrameBuffer> createVideo(OSystem& osystem)
static unique_ptr<FBBackend> createVideoBackend(OSystem& osystem)
{
#if defined(__LIB_RETRO__)
return make_unique<FrameBufferLIBRETRO>(osystem);
return make_unique<FBBackendLIBRETRO>(osystem);
#elif defined(SDL_SUPPORT)
return make_unique<FrameBufferSDL2>(osystem);
return make_unique<FBBackendSDL2>(osystem);
#else
#error Unsupported platform for FrameBuffer!
#endif

View File

@ -123,8 +123,8 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
{
StickInfo info("", stick);
myDatabase.emplace(stick->name, info);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kEmulationMode, true);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kMenuMode, true);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kEmulationMode);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kMenuMode);
}
return stick->ID;

View File

@ -29,6 +29,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
@ -60,6 +62,9 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
setDefaultMapping(Event::NoType, EventMode::kEmulationMode, updateDefaults);
setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults);
#ifdef GUI_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kEditMode, updateDefaults);
#endif // DEBUG
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -99,6 +104,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 +167,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 +224,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 +279,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 +298,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)
{
@ -356,7 +385,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 +400,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 +461,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 +501,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 +565,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},
@ -587,12 +619,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},
@ -640,6 +674,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},
@ -659,6 +775,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},
@ -666,10 +783,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},
@ -691,7 +825,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},
@ -720,7 +855,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},

View File

@ -106,6 +106,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 +133,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;

View File

@ -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);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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,

View File

@ -35,26 +35,37 @@ 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};
};
public:
PaletteHandler(OSystem& system);
virtual ~PaletteHandler() = default;
/**
Cycle through available palettes.
@ -109,6 +120,7 @@ class PaletteHandler
*/
void setPalette();
private:
static constexpr char DEGREE = 0x1c;
@ -122,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.
@ -187,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.
@ -194,7 +252,7 @@ class PaletteHandler
void loadUserPalette();
private:
static constexpr int NUM_ADJUSTABLES = 6;
static constexpr int NUM_ADJUSTABLES = 12;
OSystem& myOSystem;
@ -208,6 +266,12 @@ class PaletteHandler
const std::array<AdjustableTag, NUM_ADJUSTABLES> 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 },
@ -218,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

View File

@ -44,8 +44,8 @@ struct Point
if(c != 'x')
x = y = 0;
}
bool operator==(const Point & p) const { return x == p.x && y == p.y; }
bool operator!=(const Point & p) const { return x != p.x || y != p.y; }
bool operator==(const Point& p) const { return x == p.x && y == p.y; }
bool operator!=(const Point& p) const { return !(*this == p); }
friend ostream& operator<<(ostream& os, const Point& p) {
os << p.x << "x" << p.y;
@ -69,12 +69,17 @@ struct Size
}
bool valid() const { return w > 0 && h > 0; }
void clamp(uInt32 lower_w, uInt32 upper_w, uInt32 lower_h, uInt32 upper_h) {
w = BSPF::clamp(w, lower_w, upper_w);
h = BSPF::clamp(h, lower_h, upper_h);
}
bool operator==(const Size& s) const { return w == s.w && h == s.h; }
bool operator!=(const Size& s) const { return w != s.w || h != s.h; }
bool operator<(const Size& s) const { return w < s.w && h < s.h; }
bool operator<=(const Size& s) const { return w <= s.w && h <= s.h; }
bool operator>(const Size& s) const { return w > s.w && h > s.h; }
bool operator>=(const Size& s) const { return w >= s.w && h >= s.h; }
bool operator< (const Size& s) const { return w < s.w && h < s.h; }
bool operator> (const Size& s) const { return w > s.w || h > s.h; }
bool operator!=(const Size& s) const { return !(*this == s); }
bool operator<=(const Size& s) const { return !(*this > s); }
bool operator>=(const Size& s) const { return !(*this < s); }
friend ostream& operator<<(ostream& os, const Size& s) {
os << s.w << "x" << s.h;
@ -170,6 +175,11 @@ struct Rect
return r.left != x || r.top != y;
}
bool operator==(const Rect& r) const {
return top == r.top && left == r.left && bottom == r.bottom && right == r.right;
}
bool operator!=(const Rect& r) const { return !(*this == r); }
friend ostream& operator<<(ostream& os, const Rect& r) {
os << r.point() << "," << r.size();
return os;

View File

@ -37,7 +37,6 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RewindManager::setup()
{
myStateSize = 0;
myLastTimeMachineAdd = false;
const string& prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr.";
@ -138,7 +137,6 @@ bool RewindManager::addState(const string& message, bool timeMachine)
s.rewind(); // rewind Serializer internal buffers
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
{
myStateSize = std::max(myStateSize, uInt32(s.size()));
state.message = message;
state.cycles = myOSystem.console().tia().cycles();
myLastTimeMachineAdd = timeMachine;
@ -183,7 +181,7 @@ uInt32 RewindManager::rewindStates(uInt32 numStates)
if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE
&& myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK)
myOSystem.frameBuffer().showMessage(message);
myOSystem.frameBuffer().showTextMessage(message);
return i;
}
@ -218,7 +216,7 @@ uInt32 RewindManager::unwindStates(uInt32 numStates)
if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE
&& myOSystem.eventHandler().state() != EventHandlerState::PLAYBACK)
myOSystem.frameBuffer().showMessage(message);
myOSystem.frameBuffer().showTextMessage(message);
return i;
}
@ -256,18 +254,22 @@ string RewindManager::saveAllStates()
buf.str("");
out.putString(STATE_HEADER);
out.putShort(numStates);
out.putInt(myStateSize);
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(myStateSize);
for (uInt32 i = 0; i < numStates; ++i)
{
RewindState& state = myStateList.current();
Serializer& s = state.data;
uInt32 stateSize = uInt32(s.size());
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(stateSize);
out.putInt(stateSize);
// Rewind Serializer internal buffers
s.rewind();
// Save state
s.getByteArray(buffer.get(), myStateSize);
out.putByteArray(buffer.get(), myStateSize);
s.getByteArray(buffer.get(), stateSize);
out.putByteArray(buffer.get(), stateSize);
out.putString(state.message);
out.putLong(state.cycles);
@ -310,25 +312,27 @@ string RewindManager::loadAllStates()
if (in.getString() != STATE_HEADER)
return "Incompatible all states file";
numStates = in.getShort();
myStateSize = in.getInt();
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(myStateSize);
for (uInt32 i = 0; i < numStates; ++i)
{
if (myStateList.full())
compressStates();
uInt32 stateSize = in.getInt();
unique_ptr<uInt8[]> buffer = make_unique<uInt8[]>(stateSize);
// Add new state at the end of the list (queue adds at end)
// This updates the 'current' iterator inside the list
myStateList.addLast();
RewindState& state = myStateList.current();
Serializer& s = state.data;
// Rewind Serializer internal buffers
s.rewind();
// Fill new state with saved values
in.getByteArray(buffer.get(), myStateSize);
s.putByteArray(buffer.get(), myStateSize);
in.getByteArray(buffer.get(), stateSize);
s.putByteArray(buffer.get(), stateSize);
state.message = in.getString();
state.cycles = in.getLong();
}

View File

@ -144,7 +144,6 @@ class RewindManager
bool atLast() const { return myStateList.atLast(); }
void resize(uInt32 size) { myStateList.resize(size); }
void clear() {
myStateSize = 0;
myStateList.clear();
}
@ -176,7 +175,6 @@ class RewindManager
uInt64 myHorizon{0};
double myFactor{0.0};
bool myLastTimeMachineAdd{false};
uInt32 myStateSize{0};
struct RewindState {
Serializer data; // actual save state

View File

@ -43,11 +43,7 @@ class SoundNull : public Sound
{
Logger::info("Sound disabled.\n");
}
/**
Destructor
*/
virtual ~SoundNull() = default;
~SoundNull() override = default;
public:
/**

View File

@ -117,7 +117,7 @@ bool SoundSDL2::openDevice()
if(myIsInitializedFlag)
SDL_CloseAudioDevice(myDevice);
myDeviceId = BSPF::clamp(myAudioSettings.device(), 0u, uInt32(myDevices.size() - 1));
myDeviceId = BSPF::clamp(myAudioSettings.device(), 0U, uInt32(myDevices.size() - 1));
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
myDevice = SDL_OpenAudioDevice(device, 0, &desired, &myHardwareSpec,
@ -224,7 +224,7 @@ bool SoundSDL2::toggleMute()
string message = "Sound ";
message += enabled ? "unmuted" : "muted";
myOSystem.frameBuffer().showMessage(message);
myOSystem.frameBuffer().showTextMessage(message);
//ostringstream strval;
//uInt32 volume;
@ -282,7 +282,7 @@ void SoundSDL2::adjustVolume(int direction)
strval << percent << "%";
else
strval << "Off";
myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent);
myOSystem.frameBuffer().showGaugeMessage("Volume", strval.str(), percent);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -48,7 +48,7 @@ class SoundSDL2 : public Sound
/**
Destructor
*/
virtual ~SoundSDL2();
~SoundSDL2() override;
public:
/**

View File

@ -132,9 +132,9 @@ void StateManager::toggleTimeMachine()
myActiveMode = myActiveMode == Mode::TimeMachine ? Mode::Off : Mode::TimeMachine;
if(myActiveMode == Mode::TimeMachine)
myOSystem.frameBuffer().showMessage("Time Machine enabled");
myOSystem.frameBuffer().showTextMessage("Time Machine enabled");
else
myOSystem.frameBuffer().showMessage("Time Machine disabled");
myOSystem.frameBuffer().showTextMessage("Time Machine disabled");
myOSystem.settings().setValue(devSettings ? "dev.timemachine" : "plr.timemachine", myActiveMode == Mode::TimeMachine);
}
@ -215,7 +215,7 @@ void StateManager::loadState(int slot)
{
buf.str("");
buf << "Can't open/load from state file " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
return;
}
@ -239,7 +239,7 @@ void StateManager::loadState(int slot)
buf << "Invalid data in state " << slot << " file";
}
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
}
}
@ -261,7 +261,7 @@ void StateManager::saveState(int slot)
{
buf.str("");
buf << "Can't open/save to state file " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
return;
}
@ -274,7 +274,7 @@ void StateManager::saveState(int slot)
catch(...)
{
buf << "Error saving state " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
return;
}
@ -292,7 +292,7 @@ void StateManager::saveState(int slot)
else
buf << "Error saving state " << slot;
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
}
}
@ -307,7 +307,7 @@ void StateManager::changeState(int direction)
buf << "Changed to state slot " << myCurrentSlot;
else
buf << "State slot " << myCurrentSlot;
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -318,7 +318,7 @@ void StateManager::toggleAutoSlot()
// Print appropriate message
ostringstream buf;
buf << "Automatic slot change " << (autoSlot ? "enabled" : "disabled");
myOSystem.frameBuffer().showMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.str());
myOSystem.settings().setValue("autoslot", autoSlot);
}

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "6.3_pre"
#define STELLA_BUILD "6091"
#define STELLA_VERSION "6.5_pre"
#define STELLA_BUILD "6238"
#endif

View File

@ -0,0 +1,165 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Settings.hxx"
#include "VideoModeHandler.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoModeHandler::setImageSize(const Common::Size& image)
{
myImage = image;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoModeHandler::setDisplaySize(const Common::Size& display, Int32 fsIndex)
{
myDisplay = display;
myFSIndex = fsIndex;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const VideoModeHandler::Mode&
VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode)
{
const bool windowedRequested = myFSIndex == -1;
// TIA mode allows zooming at non-integral factors in most cases
if(inTIAMode)
{
if(windowedRequested)
{
const float zoom = settings.getFloat("tia.zoom");
ostringstream desc;
desc << (zoom * 100) << "%";
// Image and screen (aka window) dimensions are the same
// Overscan is not applicable in this mode
myMode = Mode(myImage.w * zoom, myImage.h * zoom, Mode::Stretch::Fill,
myFSIndex, desc.str(), zoom);
}
else
{
const float overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0;
// First calculate maximum zoom that keeps aspect ratio
const float scaleX = float(myImage.w) / myDisplay.w,
scaleY = float(myImage.h) / myDisplay.h;
float zoom = 1.F / std::max(scaleX, scaleY);
// When aspect ratio correction is off, we want pixel-exact images,
// so we default to integer zooming
if(!settings.getBool("tia.correct_aspect"))
zoom = static_cast<uInt32>(zoom);
if(!settings.getBool("tia.fs_stretch")) // preserve aspect, use all space
{
myMode = Mode(myImage.w * zoom, myImage.h * zoom,
myDisplay.w, myDisplay.h,
Mode::Stretch::Preserve, myFSIndex,
"Fullscreen: Preserve aspect, no stretch", zoom, overscan);
}
else // ignore aspect, use all space
{
myMode = Mode(myImage.w * zoom, myImage.h * zoom,
myDisplay.w, myDisplay.h,
Mode::Stretch::Fill, myFSIndex,
"Fullscreen: Ignore aspect, full stretch", zoom, overscan);
}
}
}
else // UI mode (no zooming)
{
if(windowedRequested)
myMode = Mode(myImage.w, myImage.h, Mode::Stretch::None);
else
myMode = Mode(myImage.w, myImage.h, myDisplay.w, myDisplay.h,
Mode::Stretch::None, myFSIndex);
}
return myMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
Int32 fsindex, const string& desc,
float zoomLevel)
: Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
Stretch smode, Int32 fsindex, const string& desc,
float zoomLevel, float overscan)
: stretch(smode),
description(desc),
zoom(zoomLevel),
fsIndex(fsindex)
{
// First set default size and positioning
screenS = Common::Size(sw, sh);
// Now resize based on windowed/fullscreen mode and stretch factor
if(fsIndex != -1) // fullscreen mode
{
switch(stretch)
{
case Stretch::Preserve:
iw *= overscan;
ih *= overscan;
break;
case Stretch::Fill:
// Scale to all available space
iw = screenS.w * overscan;
ih = screenS.h * overscan;
break;
case Stretch::None:
// Don't do any scaling at all
iw = std::min(iw, screenS.w) * overscan;
ih = std::min(ih, screenS.h) * overscan;
break;
}
}
else
{
// In windowed mode, currently the size is scaled to the screen
// TODO - this may be updated if/when we allow variable-sized windows
switch(stretch)
{
case Stretch::Preserve:
case Stretch::Fill:
screenS.w = iw;
screenS.h = ih;
break;
case Stretch::None:
break; // Do not change image or screen rects whatsoever
}
}
// Now re-calculate the dimensions
iw = std::min(iw, screenS.w);
ih = std::min(ih, screenS.h);
imageR.moveTo((screenS.w - iw) >> 1, (screenS.h - ih) >> 1);
imageR.setWidth(iw);
imageR.setHeight(ih);
screenR = Common::Rect(screenS);
}

View File

@ -0,0 +1,113 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef VIDEO_MODE_HANDLER_HXX
#define VIDEO_MODE_HANDLER_HXX
class Settings;
#include "Rect.hxx"
#include "bspf.hxx"
class VideoModeHandler
{
public:
// Contains all relevant info for the dimensions of a video screen
// Also takes care of the case when the image should be 'centered'
// within the given screen:
// 'image' is the image dimensions into the screen
// 'screen' are the dimensions of the screen itself
struct Mode
{
enum class Stretch {
Preserve, // Stretch to fill all available space; preserve aspect ratio
Fill, // Stretch to fill all available space
None // No stretching (1x zoom)
};
Common::Rect imageR;
Common::Rect screenR;
Common::Size screenS;
Stretch stretch{Mode::Stretch::None};
string description;
float zoom{1.F};
Int32 fsIndex{-1}; // -1 indicates windowed mode
Mode() = default;
Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode,
Int32 fsindex = -1, const string& desc = "",
float zoomLevel = 1.F, float overscan = 1.F);
Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1,
const string& desc = "", float zoomLevel = 1.F);
friend ostream& operator<<(ostream& os, const Mode& vm)
{
os << "image=" << vm.imageR << " screen=" << vm.screenS
<< " stretch=" << (vm.stretch == Stretch::Preserve ? "preserve" :
vm.stretch == Stretch::Fill ? "fill" : "none")
<< " desc=" << vm.description << " zoom=" << vm.zoom
<< " fsIndex= " << vm.fsIndex;
return os;
}
};
public:
VideoModeHandler() = default;
/**
Set the base size of the image. Scaling can be applied to this,
which will change the effective size.
@param image The base dimensions of the image
*/
void setImageSize(const Common::Size& image);
/**
Set the size of the display. This could be either the desktop size,
or the size of the monitor currently active.
@param display The dimensions of the enclosing display
@param fsIndex Fullscreen mode in use (-1 indicates windowed mode)
*/
void setDisplaySize(const Common::Size& display, Int32 fsIndex = -1);
/**
Build a video mode based on the given parameters, assuming that
setImageSize and setDisplaySize have been previously called.
@param settings Used to query various options that affect video mode
@param inTIAMode Whether the video mode is being used for TIA emulation
@return A video mode based on the given criteria
*/
const VideoModeHandler::Mode& buildMode(const Settings& settings,
bool inTIAMode);
private:
Common::Size myImage, myDisplay;
Int32 myFSIndex{-1};
Mode myMode;
private:
VideoModeHandler(const VideoModeHandler&) = delete;
VideoModeHandler(VideoModeHandler&&) = delete;
VideoModeHandler& operator=(const VideoModeHandler&) = delete;
VideoModeHandler& operator=(const VideoModeHandler&&) = delete;
};
#endif // VIDEO_MODE_HANDLER_HXX

View File

@ -93,6 +93,14 @@ constexpr size_t operator "" _KB(unsigned long long size)
return static_cast<size_t>(size * 1024);
}
// Output contents of a vector
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v) {
for(const auto& elem: v)
out << elem << " ";
return out;
}
static const string EmptyString("");
// This is defined by some systems, but Stella has other uses for it
@ -160,6 +168,12 @@ namespace BSPF
return (val < lower) ? upper : (val > upper) ? lower : val;
}
// Test whether the vector contains the given value
template<typename T>
bool contains(const std::vector<T>& v, const T& elem) {
return !(v.empty() || std::find(v.begin(), v.end(), elem) == v.end());
}
// Convert string to given case
inline const string& toUpperCase(string& s)
{

View File

@ -1,10 +1,13 @@
MODULE := src/common
MODULE_OBJS := \
src/common/AudioQueue.o \
src/common/AudioSettings.o \
src/common/Base.o \
src/common/EventHandlerSDL2.o \
src/common/FBBackendSDL2.o \
src/common/FBSurfaceSDL2.o \
src/common/FrameBufferSDL2.o \
src/common/FpsMeter.o \
src/common/FSNodeZIP.o \
src/common/HighScoresManager.o \
src/common/JoyMap.o \
@ -20,14 +23,12 @@ MODULE_OBJS := \
src/common/PNGLibrary.o \
src/common/RewindManager.o \
src/common/SoundSDL2.o \
src/common/StateManager.o \
src/common/TimerManager.o \
src/common/ZipHandler.o \
src/common/AudioQueue.o \
src/common/AudioSettings.o \
src/common/FpsMeter.o \
src/common/ThreadDebugging.o \
src/common/StaggeredLogger.o \
src/common/StateManager.o \
src/common/ThreadDebugging.o \
src/common/TimerManager.o \
src/common/VideoModeHandler.o \
src/common/ZipHandler.o \
src/common/repository/KeyValueRepositoryConfigfile.o \
src/common/sdl_blitter/BilinearBlitter.o \
src/common/sdl_blitter/QisBlitter.o \

View File

@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "BilinearBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb, bool interpolate)
BilinearBlitter::BilinearBlitter(FBBackendSDL2& fb, bool interpolate)
: myFB(fb),
myInterpolate(interpolate)
{

View File

@ -18,7 +18,7 @@
#ifndef BILINEAR_BLITTER_HXX
#define BILINEAR_BLITTER_HXX
class FrameBufferSDL2;
class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@ -27,9 +27,9 @@ class BilinearBlitter : public Blitter {
public:
BilinearBlitter(FrameBufferSDL2& fb, bool interpolate);
BilinearBlitter(FBBackendSDL2& fb, bool interpolate);
virtual ~BilinearBlitter();
~BilinearBlitter() override;
virtual void reinitialize(
SDL_Rect srcRect,
@ -41,7 +41,7 @@ class BilinearBlitter : public Blitter {
virtual void blit(SDL_Surface& surface) override;
private:
FrameBufferSDL2& myFB;
FBBackendSDL2& myFB;
SDL_Texture* myTexture{nullptr};
SDL_Texture* mySecondaryTexture{nullptr};

View File

@ -21,7 +21,7 @@
#include "BilinearBlitter.hxx"
#include "QisBlitter.hxx"
unique_ptr<Blitter> BlitterFactory::createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling)
unique_ptr<Blitter> BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
{
if (!fb.isInitialized()) {
throw runtime_error("BlitterFactory requires an initialized framebuffer!");

View File

@ -21,8 +21,8 @@
#include <string>
#include "Blitter.hxx"
#include "FBBackendSDL2.hxx"
#include "bspf.hxx"
#include "FrameBufferSDL2.hxx"
class BlitterFactory {
public:
@ -35,7 +35,7 @@ class BlitterFactory {
public:
static unique_ptr<Blitter> createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling);
static unique_ptr<Blitter> createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling);
};
#endif // BLITTER_FACTORY_HXX

View File

@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "QisBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
QisBlitter::QisBlitter(FrameBufferSDL2& fb)
QisBlitter::QisBlitter(FBBackendSDL2& fb)
: myFB(fb)
{
}
@ -32,7 +32,7 @@ QisBlitter::~QisBlitter()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool QisBlitter::isSupported(FrameBufferSDL2 &fb)
bool QisBlitter::isSupported(FBBackendSDL2& fb)
{
if (!fb.isInitialized()) throw runtime_error("framebuffer not initialized");

View File

@ -18,7 +18,7 @@
#ifndef QIS_BLITTER_HXX
#define QIS_BLITTER_HXX
class FrameBufferSDL2;
class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@ -27,11 +27,11 @@ class QisBlitter : public Blitter {
public:
explicit QisBlitter(FrameBufferSDL2& fb);
explicit QisBlitter(FBBackendSDL2& fb);
static bool isSupported(FrameBufferSDL2 &fb);
static bool isSupported(FBBackendSDL2& fb);
virtual ~QisBlitter();
~QisBlitter() override;
virtual void reinitialize(
SDL_Rect srcRect,
@ -44,7 +44,7 @@ class QisBlitter : public Blitter {
private:
FrameBufferSDL2& myFB;
FBBackendSDL2& myFB;
SDL_Texture* mySrcTexture{nullptr};
SDL_Texture* mySecondarySrcTexture{nullptr};

View File

@ -605,7 +605,8 @@ bool CartDebug::removeLabel(const string& label)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) const
bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead,
int places, bool isRam) const
{
switch(addressType(addr))
{
@ -662,21 +663,24 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
{
// RAM can use user-defined labels; otherwise we default to
// standard mnemonics
auto iter = myUserLabels.find(addr);
if(iter != myUserLabels.end())
{
buf << iter->second;
}
else
{
uInt16 a = addr & 0xFF, offset = addr & 0xFF00;
if((iter = myUserLabels.find(a)) != myUserLabels.end())
AddrToLabel::const_iterator iter;
uInt16 a = addr & 0xFF, offset = addr & 0xFF00;
bool found = false;
// Search for nearest label
for(uInt16 i = a; i >= 0x80; --i)
if((iter = myUserLabels.find(i)) != myUserLabels.end())
{
buf << iter->second;
else
buf << ourZPMnemonic[a - 0x80];
if(offset > 0)
buf << "|$" << Base::HEX2 << offset;
}
if(a != i)
buf << "+$" << Base::HEX1 << (a - i);
found = true;
break;
}
if(!found)
buf << ourZPMnemonic[a - 0x80];
if(offset > 0)
buf << "|$" << Base::HEX2 << offset;
return true;
}
@ -684,11 +688,28 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
case AddrType::ROM:
{
// These addresses can never be in the system labels list
const auto& iter = myUserLabels.find(addr);
if(iter != myUserLabels.end())
if(isRam) // cartridge RAM
{
buf << iter->second;
return true;
AddrToLabel::const_iterator iter;
// Search for nearest label
for(uInt16 i = addr; i >= (addr & 0xf000); --i)
if((iter = myUserLabels.find(i)) != myUserLabels.end())
{
buf << iter->second;
if(addr != i)
buf << "+$" << Base::HEX1 << (addr - i);
return true;
}
}
else
{
const auto& iter = myUserLabels.find(addr);
if(iter != myUserLabels.end())
{
buf << iter->second;
return true;
}
}
break;
}
@ -713,10 +734,10 @@ bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) con
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::getLabel(uInt16 addr, bool isRead, int places) const
string CartDebug::getLabel(uInt16 addr, bool isRead, int places, bool isRam) const
{
ostringstream buf;
getLabel(buf, addr, isRead, places);
getLabel(buf, addr, isRead, places, isRam);
return buf.str();
}

View File

@ -70,7 +70,7 @@ class CartDebug : public DebuggerSystem
public:
CartDebug(Debugger& dbg, Console& console, const OSystem& osystem);
virtual ~CartDebug() = default;
~CartDebug() override = default;
const DebuggerState& getState() override;
const DebuggerState& getOldState() override { return myOldState; }
@ -211,8 +211,10 @@ class CartDebug : public DebuggerSystem
If places is not -1 and a label hasn't been defined, return a
formatted hexidecimal address
*/
bool getLabel(ostream& buf, uInt16 addr, bool isRead, int places = -1) const;
string getLabel(uInt16 addr, bool isRead, int places = -1) const;
bool getLabel(ostream& buf, uInt16 addr, bool isRead,
int places = -1, bool isRam = false) const;
string getLabel(uInt16 addr, bool isRead,
int places = -1, bool isRam = false) const;
int getAddress(const string& label) const;
/**

View File

@ -90,21 +90,18 @@ Debugger::~Debugger()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::initialize()
{
const Common::Size& s = myOSystem.settings().getSize("dbg.res");
mySize = myOSystem.settings().getSize("dbg.res");
const Common::Size& d = myOSystem.frameBuffer().desktopSize();
myWidth = s.w; myHeight = s.h;
// The debugger dialog is resizable, within certain bounds
// We check those bounds now
myWidth = std::max(myWidth, uInt32(DebuggerDialog::kSmallFontMinW));
myHeight = std::max(myHeight, uInt32(DebuggerDialog::kSmallFontMinH));
myWidth = std::min(myWidth, uInt32(d.w));
myHeight = std::min(myHeight, uInt32(d.h));
mySize.clamp(uInt32(DebuggerDialog::kSmallFontMinW), d.w,
uInt32(DebuggerDialog::kSmallFontMinH), d.h);
myOSystem.settings().setValue("dbg.res", Common::Size(myWidth, myHeight));
myOSystem.settings().setValue("dbg.res", mySize);
delete myDialog; myDialog = nullptr;
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, mySize.w, mySize.h);
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
@ -115,12 +112,14 @@ void Debugger::initialize()
FBInitStatus Debugger::initializeVideo()
{
string title = string("Stella ") + STELLA_VERSION + ": Debugger mode";
return myOSystem.frameBuffer().createDisplay(title, FrameBuffer::BufferType::Debugger,
myWidth, myHeight);
return myOSystem.frameBuffer().createDisplay(
title, BufferType::Debugger, mySize
);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::start(const string& message, int address, bool read)
bool Debugger::start(const string& message, int address, bool read,
const string& toolTip)
{
if(myOSystem.eventHandler().enterDebugMode())
{
@ -131,6 +130,7 @@ bool Debugger::start(const string& message, int address, bool read)
if(address > -1)
buf << cartDebug().getLabel(address, read, 4);
myDialog->message().setText(buf.str());
myDialog->message().setToolTip(toolTip);
return true;
}
return false;
@ -877,23 +877,28 @@ std::array<Debugger::BuiltinFunction, 18> Debugger::ourBuiltinFunctions = { {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Names are defined here, but processed in YaccParser
std::array<Debugger::PseudoRegister, 12> Debugger::ourPseudoRegisters = { {
std::array<Debugger::PseudoRegister, 16> Debugger::ourPseudoRegisters = { {
// Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
{ "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_cycleshi", "Higher 32 bits of number of cycles since emulation started" },
{ "_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" },
{ "_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" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" }
{ "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" },
{ "_cycleshi", "Higher 32 bits of number of cycles since emulation started" },
{ "_cycleslo", "Lower 32 bits of number of cycles since emulation started" },
{ "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" },
{ "_ftimreadcycles","Number of cycles used by timer reads since frame started" },
{ "_fwsynccycles", "Number of cycles skipped by WSYNC since frame started" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" },
{ "_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)" }
// CPU address access functions:
/*{ "_lastread", "last CPU read address" },
{ "_lastwrite", "last CPU write address" },
{ "__lastbaseread", "last CPU read base address" },
{ "__lastbasewrite", "last CPU write base address" }*/
} };
//

View File

@ -44,6 +44,7 @@ class RewindManager;
#include <map>
#include "Base.hxx"
#include "Rect.hxx"
#include "DialogContainer.hxx"
#include "DebuggerDialog.hxx"
#include "FrameBufferConstants.hxx"
@ -73,7 +74,7 @@ class Debugger : public DialogContainer
Create a new debugger parent object
*/
Debugger(OSystem& osystem, Console& console);
virtual ~Debugger();
~Debugger() override;
private:
static const Int8 ANY_BANK = -1;
@ -96,7 +97,8 @@ class Debugger : public DialogContainer
@param message Message to display when entering debugger
@param address An address associated with the message
*/
bool start(const string& message = "", int address = -1, bool read = true);
bool start(const string& message = "", int address = -1, bool read = true,
const string& toolTip = "");
bool startWithFatalError(const string& message = "");
/**
@ -352,8 +354,8 @@ class Debugger : public DialogContainer
FunctionDefMap myFunctionDefs;
// Dimensions of the entire debugger window
uInt32 myWidth{DebuggerDialog::kSmallFontMinW};
uInt32 myHeight{DebuggerDialog::kSmallFontMinH};
Common::Size mySize{DebuggerDialog::kSmallFontMinW,
DebuggerDialog::kSmallFontMinH};
// Various builtin functions and operations
struct BuiltinFunction {
@ -363,7 +365,7 @@ class Debugger : public DialogContainer
string name, help;
};
static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
static std::array<PseudoRegister, 12> ourPseudoRegisters;
static std::array<PseudoRegister, 16> ourPseudoRegisters;
private:
// rewind/unwind n states

View File

@ -23,6 +23,7 @@
#include "bspf.hxx"
#include "CartDebug.hxx"
#include "CpuDebug.hxx"
#include "RiotDebug.hxx"
#include "TIADebug.hxx"
#include "Debugger.hxx"
#include "Expression.hxx"
@ -310,6 +311,18 @@ class ShiftRightExpression : public Expression
{ return myLHS->evaluate() >> myRHS->evaluate(); }
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class RiotMethodExpression : public Expression
{
public:
RiotMethodExpression(RiotMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().riotDebug()); }
private:
std::function<int(const RiotDebug&)> myMethod;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class TiaMethodExpression : public Expression
{

View File

@ -1747,9 +1747,13 @@ void DebuggerParser::executeRunTo()
// Create a progress dialog box to show the progress searching through the
// disassembly, since this may be a time-consuming operation
ostringstream buf;
buf << "RunTo searching through " << max_iterations << " disassembled instructions";
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
buf << "RunTo searching through " << max_iterations << " disassembled instructions"
<< progress.ELLIPSIS;
progress.setMessage(buf.str());
progress.setRange(0, max_iterations, 5);
progress.open();
bool done = false;
do {
@ -1763,8 +1767,8 @@ void DebuggerParser::executeRunTo()
done = (BSPF::findIgnoreCase(next, argStrings[0]) != string::npos);
}
// Update the progress bar
progress.setProgress(count);
} while(!done && ++count < max_iterations);
progress.incProgress();
} while(!done && ++count < max_iterations && !progress.isCancelled());
progress.close();
@ -1789,13 +1793,15 @@ void DebuggerParser::executeRunToPc()
uInt32 count = 0;
bool done = false;
constexpr uInt32 max_iterations = 1000000;
// Create a progress dialog box to show the progress searching through the
// disassembly, since this may be a time-consuming operation
ostringstream buf;
buf << "RunTo PC searching through " << max_iterations << " instructions";
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
progress.setRange(0, max_iterations, 5);
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
buf << " RunTo PC running" << progress.ELLIPSIS << " ";
progress.setMessage(buf.str());
progress.setRange(0, 100000, 5);
progress.open();
do {
debugger.step(false);
@ -1803,8 +1809,9 @@ void DebuggerParser::executeRunToPc()
// Update romlist to point to current PC
int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc());
done = (pcline >= 0) && (list[pcline].address == args[0]);
progress.setProgress(count);
} while(!done && ++count < max_iterations/*list.size()*/);
progress.incProgress();
++count;
} while(!done && !progress.isCancelled());
progress.close();
if(done)
@ -1953,20 +1960,24 @@ void DebuggerParser::executeStepwhile()
Expression* expr = YaccParser::getResult();
int ncycles = 0;
uInt32 count = 0;
constexpr uInt32 max_iterations = 1000000;
// Create a progress dialog box to show the progress searching through the
// disassembly, since this may be a time-consuming operation
ostringstream buf;
buf << "stepwhile running through " << max_iterations << " disassembled instructions";
ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str());
progress.setRange(0, max_iterations, 5);
ProgressDialog progress(debugger.baseDialog(), debugger.lfont());
buf << "stepwhile running through disassembled instructions"
<< progress.ELLIPSIS;
progress.setMessage(buf.str());
progress.setRange(0, 100000, 5);
progress.open();
do {
ncycles += debugger.step(false);
progress.setProgress(count);
} while (expr->evaluate() && ++count < max_iterations);
progress.incProgress();
++count;
} while (expr->evaluate() && !progress.isCancelled());
progress.close();
commandResult << "executed " << ncycles << " cycles";

View File

@ -31,7 +31,7 @@ class DebuggerState
{
public:
DebuggerState() = default;
~DebuggerState() = default;
virtual ~DebuggerState() = default;
DebuggerState(const DebuggerState&) = default;
DebuggerState(DebuggerState&&) = delete;

View File

@ -68,6 +68,8 @@ const DebuggerState& RiotDebug::getState()
myState.INTIMCLKS = intimClocks();
myState.TIMDIV = timDivider();
myState.timReadCycles = timReadCycles();
return myState;
}
@ -75,10 +77,11 @@ const DebuggerState& RiotDebug::getState()
void RiotDebug::saveOldState()
{
// Port A & B registers
myOldState.SWCHA_R = swcha();
// read from myState where other widgets can update pins directly
myOldState.SWCHA_R = myState.SWCHA_R; // swcha();
myOldState.SWCHA_W = mySystem.m6532().myOutA;
myOldState.SWACNT = swacnt();
myOldState.SWCHB_R = swchb();
myOldState.SWCHB_R = myState.SWCHB_R; // swchb();
myOldState.SWCHB_W = mySystem.m6532().myOutB;
myOldState.SWBCNT = swbcnt();
Debugger::set_bits(myOldState.SWCHA_R, myOldState.swchaReadBits);
@ -93,8 +96,9 @@ void RiotDebug::saveOldState()
myOldState.INPT1 = inpt(1);
myOldState.INPT2 = inpt(2);
myOldState.INPT3 = inpt(3);
myOldState.INPT4 = inpt(4);
myOldState.INPT5 = inpt(5);
// read from myState where other widgets can update pins directly
myOldState.INPT4 = myState.INPT4; // inpt(4);
myOldState.INPT5 = myState.INPT5; // inpt(5);
myOldState.INPTLatch = vblank(6);
myOldState.INPTDump = vblank(7);
@ -109,6 +113,8 @@ void RiotDebug::saveOldState()
myOldState.TIMCLKS = timClocks();
myOldState.INTIMCLKS = intimClocks();
myOldState.TIMDIV = timDivider();
myOldState.timReadCycles = timReadCycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -233,6 +239,24 @@ Int32 RiotDebug::timDivider() const
return mySystem.m6532().myDivider;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RiotDebug::timWrappedOnRead() const
{
return mySystem.m6532().myTimWrappedOnRead;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RiotDebug::timWrappedOnWrite() const
{
return mySystem.m6532().myTimWrappedOnWrite;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RiotDebug::timReadCycles() const
{
return mySystem.m6532().myTimReadCycles;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::diffP0(int newVal)
{

View File

@ -22,6 +22,10 @@ class M6532;
class Debugger;
class RiotDebug;
// Function type for RiotDebug instance methods
class RiotDebug;
using RiotMethod = int (RiotDebug::*)() const;
#include "DebuggerSystem.hxx"
class RiotState : public DebuggerState
@ -37,6 +41,7 @@ class RiotState : public DebuggerState
uInt8 TIM1T{0}, TIM8T{0}, TIM64T{0}, T1024T{0}, INTIM{0}, TIMINT{0};
Int32 TIMCLKS{0}, INTIMCLKS{0}, TIMDIV{0};
uInt16 timReadCycles;
// These are actually from the TIA, but are I/O related
uInt8 INPT0{0}, INPT1{0}, INPT2{0}, INPT3{0}, INPT4{0}, INPT5{0};
@ -75,6 +80,11 @@ class RiotDebug : public DebuggerSystem
Int32 timClocks() const;
Int32 intimClocks() const;
Int32 timDivider() const;
/* Debugger pseudo-registers for timer accesses */
int timWrappedOnRead() const;
int timWrappedOnWrite() const;
int timReadCycles() const;
/* Console switches */
bool diffP0(int newVal = -1);

View File

@ -149,6 +149,7 @@ const DebuggerState& TIADebug::getState()
myState.info.push_back(scanlines());
myState.info.push_back(scanlinesLastFrame());
myState.info.push_back(clocksThisLine());
myState.info.push_back(frameWsyncCycles());
return myState;
}
@ -258,6 +259,7 @@ void TIADebug::saveOldState()
myOldState.info.push_back(scanlines());
myOldState.info.push_back(scanlinesLastFrame());
myOldState.info.push_back(clocksThisLine());
myOldState.info.push_back(frameWsyncCycles());
}
/* the set methods now use mySystem.poke(). This will save us the
@ -909,6 +911,12 @@ int TIADebug::frameCycles() const
return myTIA.frameCycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::frameWsyncCycles() const
{
return myTIA.frameWSyncCycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TIADebug::cyclesLo() const
{

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