Compare commits

..

763 Commits

Author SHA1 Message Date
Stephen Anthony 7b5c19ff5e Fix warning from clang-tidy. 2025-04-19 16:11:51 -02:30
Stephen Anthony 709237c79c Fix minor warning from clang-20. 2025-04-19 12:59:04 -02:30
thrust26 b753f6eefa added joystick detection pattern for RubyQ 2025-03-29 21:14:17 +01:00
Stephen Anthony aaa6c15475 Updated included libpng to v1.6.47. 2025-03-17 15:21:17 -02:30
Stephen Anthony dccefede9b Fix minor warning from clang-tidy.
Test if commit is working on repo after reorg changes.
2025-02-16 13:34:58 -03:30
Christian Speckner 17652d9348 Attempt to fix MacOS CI. 2025-02-16 10:30:44 +01:00
Christian Speckner d9d4ea0ad4 Clarify licensing for PGO ROMs. 2025-02-16 10:24:53 +01:00
thrust26 d67ac42bbc enhanced duplicated local label handling (fixes #1067) 2025-02-13 19:54:43 +01:00
thrust26 60e07663d1 aligned gray PAL colors in standard palette (fixes #1066) 2025-02-09 00:18:09 +01:00
thrust26 4c8740f309 Merge branch 'master' of https://github.com/stella-emu/stella 2025-02-08 20:28:33 +01:00
thrust26 acaeed8322 added mirrors to 3E hotspots
adapted derived 3E+ so that it does not use the mirrors
2025-02-08 20:28:22 +01:00
Stephen Kitt 37e02b5a69 Detect _host_prefix and allow cross pkg-config (#1065)
stella fails to cross build from source on Unix-style platforms,
because ./configure hard codes the build architecture pkg-config and
thus fails finding libraries. It already has a bit of knowledge about
cross compilation and actually considers a _host_prefix for some
tools. Unfortunately, _host_prefix is not yet generally initialized
and it also does not prepend _host_prefix to pkg-config.

This fixes these issues.

Signed-off-by: Stephen Kitt <steve@sk2.org>
Co-authored-by: Helmut Grohne <helmut@subdivi.de>
2025-01-31 21:27:22 +00:00
thrust26 d4f3187ee0 added four more axis to joystick handlers (fixes #1063) 2025-01-17 20:10:42 +01:00
Stephen Anthony 122409e6f8 Include latest required vcruntime libs, so Stella can start again. 2025-01-02 17:49:47 -03:30
thrust26 34e4439729 fixed #1053 2025-01-01 09:50:33 +01:00
Stephen Anthony 9b0c8c18de Updated copyright to 2025. To anyone reading these logs, Happy New Year! 2024-12-31 19:25:08 -03:30
thrust26 108478aaab fixed problems with VS project file 2024-12-31 19:49:48 +01:00
thrust26 175d578c07 changed VS setting for PGO 2024-12-30 15:48:27 +01:00
thrust26 0852d72dc9 Merge branch 'master' of https://github.com/stella-emu/stella 2024-12-30 12:41:18 +01:00
thrust26 e4b4b08c46 fixed a bug where the combination of RAM banks and PlusROM would break a game (this should fix #1058) 2024-12-30 12:41:01 +01:00
Stephen Anthony 0197b406b8 Fixes for minor warnings from clang-tidy. 2024-12-29 17:25:05 -03:30
thrust26 727917773e code cleanup 2024-12-29 12:15:12 +01:00
thrust26 d4b5cf6659 eliminated cycles() method in TIA.hxx 2024-12-29 12:14:52 +01:00
thrust26 56a82682d5 started working on emulating VBLANK during VSYNC 2024-12-29 10:59:14 +01:00
Stephen Anthony 0933f1ae66 More const fixes, this time from suggestions from VS code analyzer. 2024-12-20 19:24:20 -03:30
Stephen Anthony 6dfef64461 Disable warnings from external libs (SDL) in VS code analysis mode. 2024-12-20 16:29:02 -03:30
Stephen Anthony 27b109b483 Fixed non UTF-8 chars. 2024-12-20 14:47:37 -03:30
jfroco abb92327c0 libretro: add reload/next game (#1059)
- Enable reload/next game option in Core options
- Map reload/next game action to X button
2024-12-18 11:41:12 +01:00
thrust26 682cdb0e28 added PAL60 signature check to auto detect display type (resolves #1061) 2024-12-17 23:03:57 +01:00
thrust26 146bec13ee moved loading of config and DASM list & symbols files before executing auto scripts 2024-12-15 22:29:25 +01:00
thrust26 13cf6aaacd slightly enhanced PlusROM display in debugger (keeps last send/receive now) 2024-12-13 09:33:15 +01:00
Stephen Anthony f744e34687 Fix potential uninitialized array access. 2024-12-10 21:23:05 -03:30
thrust26 ac64828880 fixed #1057 2024-12-09 16:09:54 +01:00
thrust26 f6b1d674db improved default NTSC custom palette 2024-12-09 15:24:38 +01:00
Stephen Anthony 6fe0e61332 Use constexpr. 2024-12-05 17:57:24 -03:30
thrust26 991a6b2447 Merge branch 'master' of https://github.com/stella-emu/stella 2024-12-01 09:33:20 +01:00
thrust26 ce37689720 improved 'help' command in debugger prompt (case insensitive now) 2024-12-01 09:33:09 +01:00
Stephen Anthony 18c1b44419 Fix whitespace. 2024-11-17 19:14:20 -03:30
SvOlli 09679fb228 Debian build requires libgtest-dev, but is not specified (#1049)
Co-authored-by: Sven Oliver Moll <svolli@svolli.de>
2024-11-10 20:13:54 +00:00
Stephen Anthony 41fa2922f9 Updated libpng to latest release. 2024-10-31 16:13:50 -02:30
Stephen Anthony e787941351 Updated httplib to latest release. 2024-10-31 16:07:37 -02:30
Stephen Anthony f2164a9637 Remove executable bit on data files. 2024-10-21 14:27:31 -02:30
Eric Warmenhoven 173a87f41b ios/tvos: properly set min supported version (#1048) 2024-10-21 15:30:52 +00:00
thrust26 5e6ef2eaf7 Merge branch 'master' of https://github.com/stella-emu/stella 2024-10-20 09:59:25 +02:00
thrust26 51b8b06e91 added missing "PlusROM support enabled" initialization 2024-10-20 09:59:15 +02:00
Stephen Anthony f77ddc6fee Match style in surrounding code for FileListWidget. 2024-10-19 16:54:47 -02:30
thrust26 6b982c8325 added PlusROM support developer option (fixes #1019) 2024-10-19 10:01:16 +02:00
thrust26 c9311529cb fixed #1047 2024-10-17 15:48:16 +02:00
Stephen Anthony 594380b2f9 Fix doc to match commit to webpage docs. 2024-10-17 10:21:29 -02:30
Stephen Anthony c003a21362 Update docs; macOS 10.13 is the minimum supported version. 2024-10-10 17:03:18 -02:30
Stephen Anthony ec8a8df269 For Windows build, remove *all* DLL's before install, and only install
SDL2.dll.
2024-10-07 17:05:27 -02:30
Stephen Anthony 3faee00fa7 Re-add ZIP build for Windows. 2024-10-07 16:28:50 -02:30
Stephen Anthony 02e0ff625b Fix misplaced PNG files. 2024-10-07 16:23:31 -02:30
Stephen Anthony dded9debdb Fixes from clang-tidy-19 that didn't make it for the last release. 2024-10-06 20:27:25 -02:30
Stephen Anthony 5d034cec3c Automatically remove old DLL's for Windows install.
This fixes exe not starting with latest release.
2024-10-06 20:25:59 -02:30
Stephen Anthony d55b1aec0d Update release to version 7. 2024-10-04 13:46:46 -02:30
Stephen Anthony 01f8382c81 Fix macOS build script. 2024-10-03 12:44:17 -02:30
Stephen Anthony d7e9b98951 Getting docs ready for 7.0 release. 2024-10-02 12:50:28 -02:30
Stephen Anthony 5ef3ebc287 Fix filename case. 2024-10-02 12:10:47 -02:30
Stephen Anthony 14eb4226a5 Update Xcode project to v16. 2024-10-02 11:37:05 -02:30
Eric Warmenhoven 56c18f57f9 libretro: fix gitlab CI (#1044) 2024-10-02 10:50:01 -02:30
thrust26 d91cdcb1ec minor doc fixes 2024-09-26 22:02:12 +02:00
Stephen Anthony 29a3f90648 Potential speedup in Windows FSNode::getChildren().
Worst case is it doesn't improve at all.
2024-09-18 20:42:24 -02:30
thrust26 323b6c9721 changed buttonLast type (fixes #1043) 2024-09-09 10:28:20 +02:00
thrust26 d577e0feeb Some fixes to ELF doc 2024-09-07 09:01:00 +02:00
Stephen Anthony 3f70246896 Updated docs, merged back changes made to live page. 2024-09-06 21:30:49 -02:30
thrust26 0cb4de07f3 updated screenshots for ELF developer options 2024-09-06 17:20:43 +02:00
Stephen Anthony 1c604d6dc2 Fix missing initializations. 2024-09-01 01:16:23 -02:30
Christian Speckner 357527370e Merge remote-tracking branch 'origin/late-hmove-experiments' 2024-08-31 18:49:51 +02:00
Christian Speckner 7f3a4d34bb Remove cast. 2024-08-29 20:49:24 +02:00
Stephen Anthony d4fd9292e1 libretro: Fix interfacing with paddle sensitivity. 2024-08-29 14:27:28 -02:30
Stephen Anthony bdaf399df1 Minor fixes for warnings from clang-tidy. 2024-08-28 21:51:40 -02:30
thrust26 78c77d0a9a Oops 2024-08-28 12:17:01 +02:00
thrust26 18eeef3be6 removed dynamic_cast
removed unused method in Debugger
2024-08-28 11:09:15 +02:00
Stephen Anthony 03a9e858cd Fix minor warnings from clang-tidy. 2024-08-27 22:27:53 -02:30
Stephen Anthony 63bcb3e22f Fix Unix build; minor formatting fixes. 2024-08-27 21:34:13 -02:30
Christian Speckner bca3892757 Finish state widget. 2024-08-27 22:07:00 +02:00
Christian Speckner e0dc373741 Fix race on startup. 2024-08-27 22:06:48 +02:00
Christian Speckner 005fa382cb Fix bad downcast. 2024-08-27 21:15:32 +02:00
Christian Speckner 0bc0843adc Add ellipsis. 2024-08-27 21:15:32 +02:00
Stephen Anthony 5bd4121064 Added missing class to Xcode project file. 2024-08-27 10:54:12 -02:30
Christian Speckner ff4d7f2e9c Add ELF state widget. 2024-08-26 22:48:12 +02:00
Stephen Anthony b7ffc112de Add missing class to Xcode project. 2024-08-26 14:37:51 -02:30
Stephen Anthony 50ea6fd00f Update sqlite to latest release. 2024-08-24 11:43:42 -02:30
Stephen Anthony 2dab3fab17 Updated httplib to latest release. 2024-08-24 11:35:16 -02:30
Stephen Anthony 414b7947a6 Fix misplaced files in Visual Studio project file. 2024-08-23 21:24:49 -02:30
Stephen Anthony df3ebd6fa9 Update libpng and zlib to latest releases. 2024-08-23 21:18:00 -02:30
Stephen Anthony 1d43d19e36 Update config.{guess,sub} to latest versions. 2024-08-23 20:52:04 -02:30
Stephen Anthony 9b631344bc Clean up Makefile a little, removing obsolete warning flags. 2024-08-23 20:45:49 -02:30
Stephen Anthony 50199cac48 Fixes for suggestions from clang-tidy; mostly missing initializations. 2024-08-23 20:00:44 -02:30
Christian Speckner 98be025035 Fixes, make sure that an error during reload is visible after the launcher starts. 2024-08-23 22:43:18 +02:00
Christian Speckner b5009a353a Improve handling of errors during console reload. 2024-08-22 13:10:12 +02:00
Christian Speckner 99fe920390 Avoid crash if strict mode is enabled, console is reloaded and linking fails. 2024-08-21 23:09:32 +02:00
Christian Speckner 40a6427d25 Ignore unresolved relocations unless ARM set to strict mode. 2024-08-21 22:46:58 +02:00
Christian Speckner 5d27786116 Implement ARM image export. 2024-08-21 22:36:54 +02:00
Christian Speckner 5756641f2c Fix build warning. 2024-08-21 10:32:24 +02:00
Christian Speckner a5c76df1b2 Add UI for saving ARM image. 2024-08-20 23:11:18 +02:00
Stephen Anthony 8e3cb19950 Adding missing class to VS project. 2024-08-20 14:32:48 -02:30
Christian Speckner be04d30134 Start work on ELF debug widget. 2024-08-20 18:49:47 +02:00
Stephen Anthony 14b93e7b55 Fix potential data loss in state save file. 2024-08-16 12:56:36 -02:30
Stephen Anthony 106413cd87 Fixes for minor clang-tidy warnings. 2024-08-14 18:42:37 -02:30
Christian Speckner b9ffb761b0 State loads. 2024-08-14 22:25:26 +02:00
Christian Speckner 8d5cd5d7b1 Refactoring, include "rom image" in save. 2024-08-14 21:21:37 +02:00
thrust26 65b56d691a updated doc for short late HMOVEs 2024-08-14 12:44:01 +02:00
Christian Speckner 1b83ef98f3 State saves. 2024-08-13 23:15:00 +02:00
thrust26 6b944f258d enhanced UI and settings for TIA glitch "short late HMOVEs" 2024-08-13 14:54:03 +02:00
thrust26 e6aebaa736 removed warning 2024-08-13 13:57:48 +02:00
Christian Speckner 2f4ce7668b Gobble movement pulse on clock 0. 2024-08-13 13:13:28 +02:00
Christian Speckner 17272af6a9 Sync time on bus snoops. 2024-08-12 21:53:34 +02:00
Christian Speckner ce659c3cd7 Force inline read methods, tread big endian the same way. 2024-08-12 21:37:38 +02:00
thrust26 ab36b0e725 added ELF speed constants everywhere 2024-08-11 20:00:46 +02:00
thrust26 20dd7ebeae Merge branch 'master' of https://github.com/stella-emu/stella 2024-08-11 19:48:23 +02:00
thrust26 4eb9319150 added reload requirement text for ELF ROMs 2024-08-11 19:48:03 +02:00
Stephen Anthony a3bd550cb3 Minor style/formatting fixes. 2024-08-11 14:25:39 -02:30
Christian Speckner 9fa896354f Move debug dump to CLI option, don't dump by default. 2024-08-11 15:59:13 +02:00
Christian Speckner 0e3fc4f3a6 Remove debug code. 2024-08-11 15:46:22 +02:00
Christian Speckner c01703ce1f Add R_ARM_REL32 . 2024-08-11 15:40:55 +02:00
Christian Speckner e61efe6765 Fix and hook up speed setting. 2024-08-11 15:21:47 +02:00
Christian Speckner 9bf342c998 Implement "strict mode". 2024-08-11 14:54:02 +02:00
thrust26 cf8d751105 fixed reordering bug 2024-08-11 12:50:10 +02:00
Christian Speckner 563c28dd66 Fix race condition with use-after-free in TimerManager. 2024-08-11 11:31:43 +02:00
Christian Speckner 417e37c51f Fix use-after-free on the audio thread when Console is destroyed. 2024-08-11 11:26:58 +02:00
Christian Speckner 412225bc04 Throw on invalid relocation type. 2024-08-11 11:26:58 +02:00
thrust26 14eac4bc62 ELF correctly sorted in display list 2024-08-11 09:22:45 +02:00
thrust26 507702ef25 replaced "cycles" with "MIPS" in DeveloperDialog 2024-08-11 08:33:25 +02:00
Christian Speckner f16c9b4c02 Remove unnecessary check. 2024-08-10 23:49:31 +02:00
thrust26 b4cb3c54a5 Merge branch 'master' of https://github.com/stella-emu/stella 2024-08-10 15:52:55 +02:00
thrust26 76dfe8563d Added new and changed existing ARM developer options
TODO: doc
2024-08-10 15:50:15 +02:00
Christian Speckner 74e25cb8e0 Set ELF system type and palette according to game props. 2024-08-10 12:35:52 +02:00
Christian Speckner dd046c4f7c Trap if add would switch instruction set. 2024-08-10 09:29:23 +02:00
Christian Speckner 434ff28458 Implement most of vcslib. 2024-08-08 22:45:46 +02:00
Christian Speckner d8bad1efc7 Silence warnings. 2024-08-08 21:57:14 +02:00
Christian Speckner c8ac92ee9f Work around clang idiosyncrasies. 2024-08-08 21:43:00 +02:00
Stephen Anthony e48c8fbedb Merge branch 'master' into elf 2024-08-07 18:00:26 -02:30
Stephen Anthony 3be7e6e4a7 Potential optimization for AudioChannel. Fix spelling mistake. 2024-08-07 17:58:12 -02:30
Stephen Anthony e4a665e7d2 Merge branch 'master' into elf 2024-08-07 12:14:59 -02:30
Stephen Anthony 7e8c868df7 Various fixes to latest sound code (style, clang-tidy, etc.) 2024-08-07 12:14:07 -02:30
Stephen Illingworth 5d68a1fd1c Improvement to volume sampling in TIA audio (#1038)
volume of audio channels sampled every on every tick. sum of samples is
averaged and a new sample output twice per scanline

this fixes issues with ROMs that change the volume of the audio multiple
times per scanline. for example, the experimental ROM in the following
thread now works correctly

https://forums.atariage.com/topic/370460-8-bit-digital-audio-from-2600/

(note that the ROM does not initialise the machine cleanly and so running
the emulator with developer options (random memory etc.) can cause
incorrect audio)
2024-08-07 10:18:42 +02:00
Stephen Anthony 4b86397f9c Fix narrowing issue. 2024-08-06 22:36:39 -02:30
Stephen Anthony 24309542e4 Replace C-style macros with C++ inlines using reinterpret_cast. 2024-08-06 22:07:50 -02:30
Stephen Anthony e574566116 Fix C-style rand(); use our Random class instead. 2024-08-06 21:42:29 -02:30
Stephen Anthony 190c9c01b0 Convert C-style union and malloc/free to C++ std::variant and unique_ptr. 2024-08-06 20:28:44 -02:30
Stephen Anthony ba1b163f92 Fix warning for potential incorrect rounding.
The proper approach is std::lround, but it won't be constexpr until C++23.
2024-08-06 16:52:08 -02:30
Stephen Anthony 934fa282ba Revert "Fix warning for rand(); NOLINT for now, as the proper fix isn't until C++23."
This reverts commit 5ce96542cb.
2024-08-06 16:50:33 -02:30
Stephen Anthony 5ce96542cb Fix warning for rand(); NOLINT for now, as the proper fix isn't until C++23. 2024-08-06 16:48:59 -02:30
Stephen Anthony 2d83fc0a26 Add `TIDY` clang-tidy script to tools. 2024-08-05 16:12:27 -02:30
Stephen Anthony bf9515f34d libretro: Run clang-tidy on all files. 2024-08-03 21:15:22 -02:30
Stephen Anthony 4e546f1891 Fixes from clang-tidy for the entire codebase, including header files. 2024-08-03 20:35:45 -02:30
Stephen Anthony 752219d4e2 Fix Visual Studio build for json header rename. 2024-08-02 16:11:39 -02:30
Stephen Anthony 428ef20a06 Rename json.hxx to json.hpp, just as it's distributed.
This has the nice side-effect of removing it from processing with clang-tidy.
2024-08-02 14:49:10 -02:30
Stephen Anthony 34a6b6979b Run clang-tidy on `src/debugger`. 2024-08-02 09:47:59 -02:30
Stephen Anthony 54538fa46c libretro: Add cart ELF support. 2024-08-01 17:29:14 -02:30
Stephen Anthony d4423d40f8 Fix Windows compile error from last commit. 2024-08-01 12:36:36 -02:30
Stephen Anthony a6d47814fd More fixes for warnings from clang-tidy, in `src/cheat` and `src/common`. 2024-08-01 12:20:40 -02:30
Stephen Anthony 4773c53f8f Fix potential overflow in cycle calculation. 2024-07-31 13:41:42 -02:30
Stephen Anthony 151becc4fb Fix compile error from last commit. 2024-07-31 13:37:38 -02:30
Stephen Anthony 86bb28d042 More fixes for warnings from clang-tidy. 2024-07-31 12:45:14 -02:30
Stephen Anthony 406f1e6956 Merge branch 'master' into elf 2024-07-30 18:03:53 -02:30
thrust26 c3b500ae61 removed interrupt handling code 2024-07-30 21:49:00 +02:00
Stephen Anthony 7c97728895 Use std::clamp. 2024-07-30 16:42:48 -02:30
thrust26 b367744e0e Fixed undefined order of startup vector peeks
Added ELF test ROMs
2024-07-30 20:52:04 +02:00
Stephen Anthony 986d631b7c Fix some clang-tidy warnings. 2024-07-30 14:52:21 -02:30
Stephen Anthony 75e54fd3ee Add ELF files to Xcode project. 2024-07-30 14:47:40 -02:30
Christian Speckner 52c51b525f Timing improvements. 2024-07-30 08:22:48 +02:00
Christian Speckner 9c54139460 Improve timing emulation, bump ARM MIPS to 190 for now. 2024-07-30 01:25:03 +02:00
Christian Speckner f0e7b122e8 Hack around buggy ARM code that accesses low memory. 2024-07-29 23:39:39 +02:00
Christian Speckner e47b2bb373 Implement init function, more vcslib -> mattress monkeys works. 2024-07-29 23:13:45 +02:00
Christian Speckner cfcec77e0b Implement more of vcslib. 2024-07-29 22:29:45 +02:00
Christian Speckner 3e1bd09b0b Fix memset. 2024-07-29 20:25:53 +02:00
Christian Speckner 7d5d19948e Minor optimizations. 2024-07-29 19:06:33 +02:00
Christian Speckner 306ec76786 Bus snooping. 2024-07-29 18:56:12 +02:00
Christian Speckner 443a14a604 Sync timing, limit the amount of queued transactions. 2024-07-29 18:21:37 +02:00
Christian Speckner 341f745684 Bus stuffing. 2024-07-28 14:13:49 +02:00
Christian Speckner e4e6878fdb Fix memset. 2024-07-28 00:12:53 +02:00
Christian Speckner d7a9ab4110 More fixes, implement more parts of vcslib. 2024-07-27 23:52:22 +02:00
Christian Speckner d2f5b74cdd Assorted fixes -> ARM executes. 2024-07-27 22:48:27 +02:00
Christian Speckner 32b8bbd32e Hook up ARM emulation. Crashes and dies right now. 2024-07-27 21:28:13 +02:00
Christian Speckner 39eb36083b Fixup thumb disassembly for debugging. 2024-07-27 21:00:32 +02:00
Christian Speckner b1e31ed032 Another stab at windows. 2024-07-27 14:25:20 +02:00
Christian Speckner 8462cdf6cd Another stab at fixing windows, set stack pointer. 2024-07-27 11:17:01 +02:00
Christian Speckner b537b6d8a9 Setup ARM for execution. 2024-07-27 10:56:40 +02:00
Christian Speckner fde5414b24 Attempt to fix windows build. 2024-07-27 00:52:26 +02:00
Christian Speckner cfaae11366 Complete vcslib bootstrap. 2024-07-27 00:49:28 +02:00
Christian Speckner e529fb6690 Refactoring. 2024-07-27 00:05:48 +02:00
Stephen Anthony ca3dea0155 Fix missing file in Xcode project. 2024-07-26 14:28:24 -02:30
Christian Speckner 2f239d90f9 Stub vcslib. 2024-07-25 23:10:05 +02:00
Christian Speckner 0dc1431397 Fix data segment mapping. 2024-07-24 23:26:56 +02:00
Christian Speckner 17c5d8a9a9 Start hooking up ARM: memory map. 2024-07-24 23:17:17 +02:00
Christian Speckner 1a4d8c442f Seems addend is calculated differently. 2024-07-23 23:10:28 +02:00
Christian Speckner e34ea5c03e Write out elf image for debugging. 2024-07-23 22:28:34 +02:00
Christian Speckner 7a20a87715 Finish (untested) cortex M0. 2024-07-23 22:00:17 +02:00
Stephen Anthony 01bdba70b0 Fix Xcode build issues. 2024-07-23 12:50:46 -02:30
Christian Speckner 1080723095 Start to adapt thumbulator. 2024-07-21 22:23:26 +02:00
Christian Speckner 00337b1a3b Finalize linker tests. 2024-07-18 22:39:07 +02:00
Christian Speckner 6e24e500db More relocation tests. 2024-07-15 22:50:23 +02:00
Christian Speckner 86315bb0e4 Tests for jump / call relocation. 2024-07-15 22:27:30 +02:00
Stephen Anthony f85d45e8bc Fix some warnings/suggestions from clang-tidy.
@DirtyHairy, hope you don't mind.
2024-07-15 13:21:26 -02:30
Christian Speckner f0b372ec3a More tests. 2024-07-14 20:28:40 +02:00
Christian Speckner 68ad6eed1f More linker tests. 2024-07-14 11:22:30 +02:00
Christian Speckner 0edc24856e Fix test setup, first slab of linker tests. 2024-07-13 23:30:21 +02:00
Christian Speckner 3486e3087e Refactor to prepare for unit tests. 2024-07-13 22:05:02 +02:00
Christian Speckner bca8a9ff07 Typo. 2024-07-13 21:50:45 +02:00
Christian Speckner a39ca385ad Introduce a separate segment for rodata. 2024-07-13 21:43:57 +02:00
Christian Speckner 523a812d84 cs 2024-07-13 20:44:02 +02:00
Christian Speckner 9f80be42f2 Wording. 2024-07-12 23:33:57 +02:00
Christian Speckner f6e8ccc220 Refactoring. 2024-07-12 23:23:27 +02:00
Christian Speckner a1b7745904 Init an preinit arrays. 2024-07-12 23:05:11 +02:00
Christian Speckner a5f9f1d351 Refactoring, fixes, lookup tables. 2024-07-12 21:52:18 +02:00
Christian Speckner b29826ee93 Fixes + stubs. 2024-07-11 23:19:06 +02:00
Christian Speckner 732d4ea4e1 BL / B.W encoding tests 6 fixes. 2024-07-11 23:19:06 +02:00
Christian Speckner 7d2b40672a Formatting. 2024-07-11 23:19:06 +02:00
Stephen Anthony 3ad74cdeb9 Fix build and warnings for Xcode project. 2024-07-11 13:16:38 -02:30
Christian Speckner fa4558526d Logging. 2024-07-11 00:57:34 +02:00
Christian Speckner 0590819119 Pull in gtest for unit tests. 2024-07-11 00:57:16 +02:00
Christian Speckner bd44bd2f8f Refactoring, fix external function pointers. 2024-07-10 08:35:47 +02:00
Christian Speckner dc6a88e61f Logging. 2024-07-10 08:28:45 +02:00
Christian Speckner 7c4022c30c Woefully untested ELF linker. 2024-07-09 20:11:35 +02:00
Christian Speckner 0f9be132e0 More cleanup. 2024-07-07 13:20:10 +02:00
Christian Speckner 01f53cec6d Refactoring. 2024-07-07 09:34:17 +02:00
Christian Speckner 436f9888a5 Cleanup. 2024-07-07 09:25:37 +02:00
Christian Speckner b38d9ad537 Fixes, load and parse relocations. 2024-07-05 23:57:12 +02:00
Christian Speckner 204ff51409 Include info in section. 2024-07-05 23:00:33 +02:00
Christian Speckner 9be997a0f4 Style, paranoia. 2024-07-05 22:57:24 +02:00
Stephen Anthony 25d06c2770 Fix Windows build. 2024-07-04 20:40:07 -02:30
Christian Speckner 923d32268a Parse symbols. 2024-07-04 23:27:14 +02:00
Christian Speckner 962bddae9b Minor refactoring. 2024-07-04 22:04:06 +02:00
Christian Speckner 80c686fc62 Port and hook up ELF basic parser. 2024-07-02 22:39:05 +02:00
Christian Speckner 15cb626994 Style. 2024-07-01 00:09:56 +02:00
Christian Speckner ae9b558bc5 Refactoring, properly model bus activity. 2024-07-01 00:08:36 +02:00
Christian Speckner 1fb7053411 Boot into overblank. 2024-06-30 17:16:32 +02:00
Stephen Anthony 4b80a12661 Fix file permissions. 2024-06-30 11:29:29 -02:30
Christian Speckner f4837ec174 Fix ELF signature detection, read value stream. 2024-06-30 11:56:07 +02:00
Christian Speckner 64126610be Fix windows build. 2024-06-30 11:03:05 +02:00
Christian Speckner 3b018602e2 Fix division by zero. 2024-06-30 11:00:46 +02:00
Christian Speckner ccfe94d616 Sttub and hook up ELF cartridge. 2024-06-30 10:30:41 +02:00
thrust26 c8b38099e8 ELF doc updates 2024-06-23 23:10:38 +02:00
thrust26 28caaa6cc0 spelling 2024-06-22 21:09:01 +02:00
thrust26 f6beb2c39a added link for Mediafire launcher images and bezels 2024-06-22 21:06:27 +02:00
Stephen Anthony 6298093c3f Fix warning from clang-tidy.
Original code is left there, commented out, since the intent isn't clear.
2024-06-14 21:41:53 -02:30
Stephen Anthony 45fe09d037 Replace Map::find with Map::contains where appropriate. 2024-06-14 18:51:58 -02:30
thrust26 9d10519857 Merge branch 'master' of https://github.com/stella-emu/stella 2024-06-14 09:20:15 +02:00
thrust26 73de4a6258 small disassembler fix to avoid dirty mirror addresses in code 2024-06-14 09:19:51 +02:00
Stephen Anthony bfe59b00b5 Oops, pruned a little too much in last commit. 2024-06-13 20:49:53 -02:30
Stephen Anthony 37a9c6587d Remove workaround for missing C++20 support.
Since this is only one required of many, and the rest can't be worked around, there's really no point to keep this one either.
2024-06-13 20:35:58 -02:30
thrust26 0d99e2874b Enhanced E7 disassembling 2024-06-12 14:05:43 +02:00
thrust26 2755caaf0f fixed underflow in FrameLayoutDetector 2024-06-12 09:48:53 +02:00
Stephen Anthony d9ab573603 libretro: Fix Makefile for recently added cart classes. 2024-06-07 22:34:09 -02:30
thrust26 2b603a3776 improved disassembly of immediate color loads 2024-06-05 19:32:40 +02:00
Stephen Anthony 78b671e20d Updated Xcode project for CartJANE. 2024-06-05 11:19:23 -02:30
thrust26 69feb2fb08 Added JANE bankswitching (for Tarzan prototype) 2024-06-05 15:27:41 +02:00
thrust26 0efa910af4 Merge branch 'master' of https://github.com/stella-emu/stella 2024-06-04 09:51:58 +02:00
thrust26 d19f9d88aa added check which ignores invalid frames (too many scanlines) during frame detection (fixes Tarzan) 2024-06-04 09:51:47 +02:00
Stephen Anthony 08098d89d4 Update Xcode project. 2024-06-03 11:50:18 -02:30
thrust26 75735c9d0b Merge branch 'master' of https://github.com/stella-emu/stella 2024-06-03 13:27:23 +02:00
thrust26 2d1cb7d24c added option to enable thumb cycle counting via emulated ROM 2024-06-03 13:27:10 +02:00
Christian Speckner 13bb5d61bb Remove logging code. 2024-06-02 19:27:11 +02:00
Christian Speckner dcaa48565d Try to update xcode version. 2024-06-02 19:21:28 +02:00
Christian Speckner cfb9ebd91a More logging. 2024-06-02 18:59:38 +02:00
Christian Speckner cdb923628a Dump MacOS version, arch. 2024-06-02 17:31:33 +02:00
Christian Speckner 9a0437aa2f Ups, wrong line. 2024-06-02 12:18:33 +02:00
Christian Speckner fe8c0a0b66 Log clang and gcc (alias?) version in CI / MacOS. 2024-06-02 12:18:01 +02:00
Christian Speckner 3f72999e44 Add W(T)F8 to XCode build. 2024-06-01 00:10:47 +02:00
thrust26 f891b9dd0a updated doc for WF8 2024-05-30 19:48:50 +02:00
thrust26 6008bdd48a added WF8 (Todo: doc) 2024-05-30 19:25:36 +02:00
thrust26 a28c57f93d added WF8 detection and test ROMs
(cherry picked from commit 28050d5d9cfa502b4f0214c2b9e322a36dc0c4bf)
2024-05-30 19:20:15 +02:00
thrust26 275e4a4f51 fix Linux builds
(cherry picked from commit 2ed846e53004a535c68153057d0646e04f9d4302)
2024-05-30 19:14:13 +02:00
thrust26 2beb93b28e added missing new files
(cherry picked from commit 29c5578f8cb014b57740bc56e5382fa303449b8a)
2024-05-30 19:14:13 +02:00
thrust26 156626fc1c added WF8 bankswitching (TODO: doc and autodetect)
(cherry picked from commit 4814f216cd69f5382b85f961e8729c4fc28f115e)
2024-05-30 19:14:12 +02:00
Stephen Anthony 82c975fbae Attempt to fix C++20 'compliant' compilers that don't actually support <numbers>. 2024-05-13 21:00:15 -02:30
Stephen Anthony f9cd1f0dc5 More 'using enum' in places where it seems appropriate. 2024-05-12 18:24:55 -02:30
Stephen Anthony 085e1737b3 Fix spelling mistake in nearestNeightBour.
Use new C++20 feature 'using enum ...' in switch statements.
I'm not convinced this is best in all cases; for now I use it sparingly.
2024-05-10 21:21:03 -02:30
Stephen Anthony 8217b08128 Fixed string vs. string_view code that works in VS but not gcc/clang. 2024-05-10 20:51:40 -02:30
Stephen Anthony 5fd6e2328b Convert stringstream::str() to stringstream::view() where applicable. 2024-05-10 20:33:04 -02:30
Stephen Anthony cb80c00629 Revert "More cleanups."
This reverts commit fdc1f106f8.

Oops, a little too eager here.
2024-05-09 20:10:55 -02:30
Stephen Anthony fdc1f106f8 More cleanups. 2024-05-09 19:59:51 -02:30
Stephen Anthony 7ea1cc650f More C++20 additions, fix Windows build failures. 2024-05-09 19:50:19 -02:30
Stephen Anthony 4d67dcbaf7 Oops, forgot an include in last commit. 2024-05-09 19:29:40 -02:30
Stephen Anthony 5ec4915301 Some C++20 additions. 2024-05-09 19:26:20 -02:30
thrust26 36f3f26ffa made joystick default controller for libretro.cxx
fixed libretro VS project
2024-05-09 18:34:41 +02:00
Eric Warmenhoven 78ff25f0f9 On older Xcode/g++ versions the c++20 standard was called c++2a. (#1031) 2024-05-09 10:47:50 -02:30
Stephen Anthony 43debd45d5 Simplified Windows InnoSetup for 64-bit only builds. 2024-05-08 20:17:50 -02:30
Stephen Anthony 017a4d1444 Remove 32-bit builds from CI on Github and Gitlab. 2024-05-08 19:47:40 -02:30
Stephen Anthony 45acce752d Remove 32-bit builds; going forward, only 64-bit is supported. 2024-05-08 19:44:13 -02:30
Stephen Anthony 20f714c5d5 Fix CI compiling for Windows. 2024-05-08 19:35:32 -02:30
Stephen Anthony a0a0232f4d Move codebase to requiring C++20, and fix resultant non-standard code. 2024-05-08 19:13:23 -02:30
thrust26 b57549e029 improved QuadTari auto detection and setup 2024-05-07 17:14:40 +02:00
thrust26 305ad0551a enabled warning for extra qualifier errors 2024-05-06 21:33:43 +02:00
thrust26 6920160d81 fixed compile error 2024-05-06 20:44:01 +02:00
thrust26 6e260274d9 added auto detection for QuadTari controllers 2024-05-06 19:32:14 +02:00
thrust26 5bf3dba8c9 minor property update (2/2) 2024-05-04 00:12:10 +02:00
thrust26 4446232c6a Merge branch 'master' of https://github.com/stella-emu/stella 2024-05-03 07:56:19 +02:00
thrust26 55251c6507 minor property update 2024-05-03 07:56:03 +02:00
Stephen Anthony 18ff42d25f Fixes for suggestions from clang-tidy. 2024-05-01 17:25:29 -02:30
Stephen Anthony 6d5235c1b8 Minor syntax corrections. 2024-04-04 14:25:47 -02:30
lodefmode 01c5ac3a33 MVC: Stay in title mode when valid file not found. (#1023) 2024-04-04 14:18:32 -02:30
lodefmode 268f357b13 Reach first/last movie frame, show both fields and mute. (#1020) 2024-03-08 15:19:43 -03:30
thrust26 3db62a8f3b Fixed MVC debugger crash 2024-03-07 20:55:29 +01:00
thrust26 359f40028e Fixed PlusROM detection (fixes #1021) 2024-03-07 18:28:52 +01:00
thrust26 1c3fcebc4b another overflow fix (see #1017) 2024-03-03 11:56:45 +01:00
Christian Speckner 74855eee78 Fix overflow. 2024-03-03 11:31:18 +01:00
thrust26 52fd4b8393 fixed #1018 2024-02-29 21:17:37 +01:00
Stephen Anthony 212b023ac8 Refactor a little; SDL-specific header stuff should stay in SDL_lib.hxx. 2024-02-02 11:23:36 -03:30
Stephen Anthony 1aee7b9246 libretro: fix #1013 2024-02-02 11:10:13 -03:30
Stephen Anthony d89b74b36c Disable various URL buttons if using a version of SDL that doesn't support it. 2024-02-02 00:29:29 -03:30
Stephen Anthony 264dcf884b Fixed minor clang warning. 2024-02-01 12:29:57 -03:30
Christian Speckner 86f847115f Fix life display in solaris. 2024-01-31 21:07:22 +01:00
thrust26 08abd79850 fixed and adjusted build w/o IMAGE_SUPPORT 2024-01-31 19:57:42 +01:00
thrust26 5fc82a66b2 fixed #1011 2024-01-30 17:27:53 +01:00
thrust26 95d3be60f0 made random hotspots peeks a developer option
added check for duplicate hotkeys
2024-01-30 15:40:48 +01:00
Stephen Anthony 41abca8a29 Fix minor warnings from clang. 2024-01-26 13:08:24 -03:30
thrust26 822837aefd enhanced and optimized auto-phosphor 2024-01-25 12:24:18 +01:00
thrust26 15cb66df0e added many phosphor properties 2024-01-24 13:24:56 +01:00
thrust26 580b86904b added auto-phosphor (resolves #1009) 2024-01-24 11:24:21 +01:00
thrust26 01a0941ffb slightly optimized movementTick
copied movementTick comments from ball to player and missile
2024-01-20 10:29:34 +01:00
thrust26 c902f94e99 added Cosmic Ark to profiled ROMs (starfield effect) 2024-01-19 09:41:17 +01:00
thrust26 7f8a1f9e8a updated WhatsNewDialog 2024-01-18 16:15:02 +01:00
thrust26 d87b7b793f minor doc update 2024-01-13 19:37:17 +01:00
thrust26 a4e8a5e4b5 Merge branch 'master' of https://github.com/stella-emu/stella 2024-01-13 11:16:57 +01:00
thrust26 780edfe9bd some random ROM polishing 2024-01-13 11:16:47 +01:00
Stephen Anthony 8b79368b2e Fixed up current changelog for interim 6.7.1 release. 2024-01-12 16:13:07 -03:30
thrust26 2365f65b2e minor property updates 2024-01-12 19:51:53 +01:00
thrust26 02b204d1b9 added random ROM loading option (resolves #995) 2024-01-11 10:11:20 +01:00
thrust26 e9dff90979 more work on bezel name properties 2024-01-07 10:50:10 +01:00
thrust26 ba4184fc61 cleaned and updated bezel name properties 2024-01-06 12:00:54 +01:00
thrust26 942e0659cf added detected bezel name to GameInfoDialog 2024-01-06 10:28:02 +01:00
thrust26 c44a7abe0a Merge branch 'master' of https://github.com/stella-emu/stella 2024-01-06 10:26:30 +01:00
thrust26 bca1f9e2a9 fixed empty file listing bug 2024-01-06 10:26:20 +01:00
Stephen Anthony bb419a7c69 Moved some changes from 7.0 into 6.7.1. 2024-01-05 22:01:13 -03:30
thrust26 2252be4a86 block keyboard directory navigation in files-only mode 2024-01-05 22:39:36 +01:00
thrust26 2e2c870e38 added file browser button for bezel selection 2024-01-05 22:23:44 +01:00
thrust26 157ce930ae fixed swapped parameters 2024-01-05 22:16:52 +01:00
lodefmode 87324ed3fa Reach first/last movie frame, show both fields and mute. (#1003) 2024-01-04 08:52:04 +01:00
thrust26 a729d207eb added lots of bezels (using ChatGpt and Python) 2024-01-03 21:39:27 +01:00
Stephen Anthony 175756dd1f Bumped copyright for 2024. Happy New Year for anyone following these commits! 2024-01-01 12:38:25 -03:30
thrust26 4e4bf34e62 final update for 2023 (properties again) 2023-12-31 16:53:08 +01:00
thrust26 08fa71141f updated properties (mostly PAL-60 added) 2023-12-29 13:06:58 +01:00
thrust26 eb8985762f updated/added properties for Turbo 2023-12-13 20:17:23 +01:00
thrust26 5a48ed79c5 worked on PAL palette (brighter) 2023-11-26 15:43:19 +01:00
Stephen Anthony f2350d5d18 clang-tidy: Fix a few remaining warnings. 2023-11-17 18:58:05 -03:30
Stephen Anthony d7ab11d7d5 Minor fixes for Xcode. 2023-11-17 12:40:01 -03:30
Stephen Anthony c315bd6655 clang-tidy: convert 'endl' to '\n' for performance. 2023-11-16 14:34:02 -03:30
Stephen Anthony 0d0a5a1ddf clang-tidy: Remove redundant header includes. 2023-11-16 12:26:39 -03:30
thrust26 81d6628bd8 fixed spelling 2023-11-14 20:32:48 +01:00
thrust26 c3d4c2c36d Merge branch 'master' of https://github.com/stella-emu/stella 2023-11-14 20:30:57 +01:00
thrust26 208aca7e9a added trace logging like z26 (fixes #204) 2023-11-14 20:30:42 +01:00
Stephen Anthony d36a33098d Fix 'dangling else' warning from clang. 2023-11-08 19:07:38 -03:30
thrust26 43ff2cd1e2 Revert "enhanced color switches"
This reverts commit 6a4c4668e3.
2023-11-04 17:50:26 +01:00
thrust26 6a4c4668e3 enhanced color switches
enhanced Stella version information
2023-11-04 17:37:29 +01:00
Stephen Anthony 687d4ace0e Updated included libpng and zlib to latest release. 2023-10-25 22:18:46 -02:30
thrust26 201d7da936 Merge branch 'master' of https://github.com/stella-emu/stella 2023-10-16 17:42:25 +02:00
thrust26 dcde9bd35b fixed missing events in debugger 2023-10-16 17:42:18 +02:00
Stephen Anthony 85b9738b2a Fixes for suggestions from clang-tidy. 2023-10-15 13:53:46 -02:30
thrust26 aaae28287f Merge branch 'master' of https://github.com/stella-emu/stella 2023-10-02 10:04:17 +02:00
thrust26 8aca3ce406 added that peeks to ROM hotspots return random values 2023-10-02 10:04:05 +02:00
Stephen Anthony 06581eb845 Fix minor warnings from clang. 2023-09-23 18:34:02 -02:30
lodefmode 83c5920810 Movie Cart PAL format (#990)
* MVC format expanded to include vsync, vblank, overscan, visible, and framerate.
Allows for playback of various formats including, PAL.

* Match MovieCart title screen format to detected timing.
Does not affect encoded video content, just title screen.

* simple moviecart PAL examples

---------

Co-authored-by: LoDef Mode <lodef.mode@gmail.ca>
2023-09-16 15:43:25 +02:00
thrust26 9e5da28a65 fixed comments and minor enhancement in CartFE 2023-09-15 13:52:39 +02:00
thrust26 af7f02f0e9 minor RomImageWidget polishing 2023-09-15 11:10:34 +02:00
thrust26 3004121685 changed FE bankswitching code to support up to 8 banks 2023-09-15 08:44:02 +02:00
thrust26 cd1dc3aea2 Merge branch 'master' of https://github.com/stella-emu/stella 2023-09-14 20:01:25 +02:00
thrust26 0a89640b44 fixed warnings 2023-09-14 20:01:13 +02:00
Christian Speckner e11f04fe51 Remove -Weverything 2023-09-14 19:48:49 +02:00
thrust26 972d3e2f0c fixed build without image support 2023-09-14 19:37:27 +02:00
Stephen Anthony 7bd3bf6e39 Fix ROM audit in Windows (fixes #988). 2023-09-12 19:42:15 -02:30
Stephen Anthony 066d948983 Fix missing first char when navigating ZIP files (fixes #989). 2023-09-12 13:57:23 -02:30
thrust26 63543e825a minor property fix 2023-09-12 16:44:56 +02:00
thrust26 2754edd176 enhanced CartCV to support small ROMs (Part 3) 2023-09-12 11:22:45 +02:00
thrust26 140657c453 enhanced CartCV to support small ROMs (Part 2) 2023-09-11 23:41:23 +02:00
thrust26 4c74e61039 enhanced CartCV to support small ROMs 2023-09-11 22:26:01 +02:00
Stephen Anthony ccecfe8717 Add bezel class to Xcode project. 2023-09-05 14:03:45 -02:30
Stephen Anthony 5724632520 Fix minor warnings from clang. 2023-09-02 01:08:05 -02:30
thrust26 3d6cb7148f added ROM image widget to tab order and moved event handling into it
added launcher list paging events for controllers
2023-09-01 11:44:59 +02:00
thrust26 5bfa377b00 some polishing for LauncherDialog (incl. doc) 2023-08-31 23:11:13 +02:00
thrust26 403d6859ea fixed #984 2023-08-31 21:43:10 +02:00
thrust26 d8db5e869e added keyboard and controller support for image zooming 2023-08-31 19:57:45 +02:00
thrust26 7631123e1f reworked some comments 2023-08-31 18:09:19 +02:00
thrust26 f1688288d6 added launcher image zooming 2023-08-31 17:59:51 +02:00
Christian Speckner 69969ab866 Never use alpha blending for source surfaces in QIS. 2023-08-30 22:40:52 +02:00
Christian Speckner babef459b0 Account for HiDPI scaling when validating QIS blitter. 2023-08-30 22:40:31 +02:00
Christian Speckner 37bad6befc Fix allocation. 2023-08-29 23:33:04 +02:00
thrust26 a8c75b5c5a fixed build without IMAGE_SUPPORT 2023-08-29 23:20:19 +02:00
thrust26 236322c2cb next oops 2023-08-29 16:41:09 +02:00
thrust26 6d8101454b a few more bezel property updates 2023-08-29 16:19:05 +02:00
thrust26 5d72ba12f7 Improved error handling when loading bezels 2023-08-29 13:51:10 +02:00
thrust26 c1ca4db5da minor CartDetector and property update 2023-08-29 13:50:23 +02:00
thrust26 3ddcc22d10 fixed zoom when switching bezel paths 2023-08-28 11:16:27 +02:00
thrust26 4c19253805 extended list of known renderers to latest SDL 2023-08-28 09:07:22 +02:00
thrust26 b821415cc0 fixed zoom clamping 2023-08-27 22:39:50 +02:00
thrust26 11607b69b4 Revert "experimenting with not clearing the framebuffer during emulation"
This reverts commit ee1f0e2999.
2023-08-27 22:37:55 +02:00
thrust26 3ad95c9ba2 improved the code for rendering non-rounded bezels only on load (this should work) 2023-08-27 16:57:36 +02:00
thrust26 e0523ddeeb minor zoom fix 2023-08-27 11:13:37 +02:00
thrust26 ebb2467f38 fixed BrowserDialog reuse
defined bezel help links
2023-08-27 11:05:33 +02:00
thrust26 ee1f0e2999 experimenting with not clearing the framebuffer during emulation
added rounded bezel auto-detection and handling
2023-08-27 10:16:45 +02:00
thrust26 2b025249f5 oops 2023-08-27 08:14:02 +02:00
thrust26 27bf99717d reversed parameter order in FrameBuffer::renderTIA 2023-08-27 08:00:14 +02:00
Stephen Anthony 5262d66216 libretro: fix build issues with new bezel code. 2023-08-26 14:42:52 -02:30
thrust26 c6e798b5a0 fix current zoom level when enabling bezels 2023-08-26 18:21:58 +02:00
Stephen Anthony 97587960fc Fixes for warnings from clang. 2023-08-26 12:23:06 -02:30
thrust26 044bffc806 aligned VS project filters with folder structure 2023-08-26 14:54:07 +02:00
thrust26 f9d9a3aa68 Merge remote-tracking branch 'remotes/origin/feature/bezels' 2023-08-26 14:06:31 +02:00
thrust26 c51d7be893 the usual IX fix 2023-08-26 14:02:44 +02:00
thrust26 776acc4533 added bezel hotkeys
renamed bezel settings
moved Bezel class to common
2023-08-26 13:50:39 +02:00
thrust26 44056ef7b3 added bezel docs 2023-08-26 13:40:36 +02:00
thrust26 3f1d80deef more bezel property updates 2023-08-26 13:39:10 +02:00
thrust26 839724cbae added more bezel properties 2023-08-26 09:03:44 +02:00
thrust26 c0bc013505 a few minor changes 2023-08-25 21:31:17 +02:00
Stephen Anthony 90d667de43 Updated sqlite3 to latest version (3.43.0). 2023-08-25 13:47:20 -02:30
thrust26 8988df04c9 updated bezel properties and matching 2023-08-25 18:12:07 +02:00
thrust26 ae8d587f3b IX fix #2 2023-08-25 17:04:55 +02:00
thrust26 5c5a1e37bf IX fix 2023-08-25 16:41:51 +02:00
thrust26 fc34df3516 refactored bezel code
added variable bezel window support
2023-08-25 15:57:21 +02:00
Stephen Anthony e7f15ba665 Fix compile error for libretro, and minor warnings from clang. 2023-08-24 12:31:06 -02:30
thrust26 cc818ed9c5 reverted to working (fixed) borders 2023-08-23 18:03:36 +02:00
thrust26 32cbd2c38f added bezel borders 2023-08-23 17:47:58 +02:00
thrust26 991de73177 IX build fix 2023-08-22 15:48:06 +02:00
thrust26 229c5ab1f7 added automatic bezel name generation 2023-08-22 14:54:09 +02:00
thrust26 ac1bbf7183 added missing change 2023-08-21 22:51:43 +02:00
thrust26 6acb7a6412 added property for bezel file names 2023-08-21 22:34:33 +02:00
thrust26 3782a4fe7e preliminary doc updates 2023-08-21 13:01:23 +02:00
thrust26 2202f58901 fixed bezel blend mode bug (only showed with TV-effects && Interpolation enabled)
changed default hotkey for correct aspect ratio
2023-08-21 10:50:47 +02:00
thrust26 6b38bc3f5a fixed info message positioning
made image paths changeable without restart
2023-08-20 07:46:33 +02:00
thrust26 56d6cb8926 some small fixes 2023-08-19 19:25:50 +02:00
thrust26 8d8bea8525 bezels working now (TODO: testing, doc) 2023-08-19 18:12:32 +02:00
thrust26 5fb2cc8d8c some changes for alpha channel support (still doesn't work :( ) 2023-08-17 20:31:42 +02:00
thrust26 868a3eeef3 first try 2023-08-17 18:18:15 +02:00
thrust26 aaa10ea414 fixed duplicate events (menu + emulation) in debugger 2023-08-16 07:28:35 +02:00
Stephen Anthony 7f9a595c22 Updated Xcode for recent class additions. 2023-08-07 13:45:02 -02:30
thrust26 beef0bd457 trying to fix Linux build 2023-08-05 15:43:56 +02:00
thrust26 4e60a6b0db added 03E0 bankswitching for Brazilian Parker Bros ROMs (resolves #887) 2023-08-05 15:20:46 +02:00
thrust26 d8636f764b added a tweak which allows searching for ROM names containing a space without starting the ROMs 2023-08-04 15:14:27 +02:00
thrust26 3714f634da update doc for removed "show all files" option
eliminated magic number for initially focus widget in LauncherDialog.cxx
2023-08-04 09:20:35 +02:00
thrust26 4a74ea10fc added some extra description for the controller port assignment 2023-08-03 18:18:03 +02:00
Stephen Anthony 08c4c68b74 Remove 'launcherroms' option, in the process fixing #851. 2023-08-02 18:19:50 -02:30
Stephen Anthony e25c427557 A cleaner fix for the last commit. 2023-08-02 13:25:22 -02:30
Stephen Anthony 0d8f62c996 Fix error using string_view where string is expected. This needs to be fixed in json eventually. 2023-08-02 13:12:56 -02:30
Stephen Anthony 6cff524e32 Fixes for minor clang warnings. 2023-08-02 12:52:12 -02:30
thrust26 0fe232ffd3 added default mapping controller port option (resolves #897) 2023-08-02 17:03:57 +02:00
Stephen Anthony 26d0eb5c01 Some cleanup of CartAR class, in preparation for moving some code from System class. 2023-08-01 17:44:44 -02:30
Stephen Anthony ded5074d11 Some optimizations to FSNodePOSIX. 2023-07-01 22:05:05 -02:30
Stephen Anthony db7fd59423 Potential speedup in FSNodeWINDOWS::getSize(). 2023-06-30 22:40:05 -02:30
Stephen Anthony 608ed4f748 Update Xcode project to recommended settings. 2023-06-22 10:54:00 -02:30
Stephen Anthony 95c49d764b Add missing class to Xcode. 2023-06-22 10:53:03 -02:30
thrust26 abd4e5c8d9 added tootips to Options dialog (resolves #977) 2023-06-15 13:31:44 +02:00
Stephen Anthony 868b2fd7cb Minor fixes for suggestions from clang-tidy. 2023-06-14 19:47:17 -02:30
thrust26 9659a0a9af reordered cart detection order to improve correct detection rate 2023-06-14 14:08:11 +02:00
thrust26 07cf16aa27 fixed some warnings in VS 2023-06-14 09:58:31 +02:00
thrust26 ef55d93525 minor fixes 2023-06-14 09:51:37 +02:00
thrust26 f572ab0946 added phosphor to Amidar game properties 2023-06-14 09:50:56 +02:00
thrust26 33cd6bf4f2 fixed QuadTari mapping storage 2023-06-12 17:45:18 +02:00
thrust26 f0bd196372 Merge branch 'master' of https://github.com/stella-emu/stella 2023-06-11 19:44:53 +02:00
thrust26 479a077e0e trying to fix #974 2023-06-11 19:44:41 +02:00
Stephen Anthony 9b65e6a2e4 Adding missing include (fixes #971). 2023-06-04 19:26:27 -02:30
thrust26 d8ee31ec1f minor fixes for GL bankswitching 2023-06-04 14:24:32 +02:00
thrust26 307b36b8c4 Merge branch 'master' of https://github.com/stella-emu/stella 2023-06-03 21:03:24 +02:00
thrust26 6c6eaed995 added limited GameLine Master Module bankswitching support 2023-06-03 21:03:07 +02:00
Stephen Anthony c10bc4d83e Update sqlite3 library. 2023-05-16 18:58:46 -02:30
thrust26 76eec054a6 changed CommaVid ROMs to 4K size (fixes #969) 2023-05-09 12:26:12 +02:00
Stephen Anthony 3bcce2c481 Oops, wrong commit last time; fix compile error in gcc 13. 2023-05-05 16:49:00 -02:30
Stephen Anthony 7e20db0210 Fixed compile error in gcc 13. 2023-05-05 16:26:47 -02:30
thrust26 d0e066eb22 Merge branch 'master' of https://github.com/stella-emu/stella 2023-05-03 19:04:15 +02:00
thrust26 a3fa688819 Added note for special chars in Windows filenames 2023-05-03 19:03:58 +02:00
Stefan aa38cb79b6 Fixed typos (#966)
Thanks for the PR.
2023-04-27 13:50:04 -02:30
Stephen Anthony 99cb62f6d3 Minor fixes from clang-tidy. 2023-04-17 16:59:44 -02:30
thrust26 197203e8f6 added missing PlusROM support for E7 bankswitching (fixes #965) 2023-04-09 15:18:24 +02:00
Thomas Jentzsch 989fecc351 enhanced/fixed some controller default mappings 2023-03-26 10:23:38 +02:00
Thomas Jentzsch 6726089791 2nd Libretro fix attempt 2023-03-24 18:59:30 +01:00
Thomas Jentzsch 7e41759b04 trying to fix Libretro pipeline build error 2023-03-24 17:46:36 +01:00
Thomas Jentzsch 10b133c50f fixed libretro builds 2023-03-24 16:24:06 +01:00
Thomas Jentzsch fe99919dd0 added right controller KEYBOARD properties for Star Raiders (auto detected as Joy 2B+) 2023-03-19 17:56:16 +01:00
Thomas Jentzsch 920d9ce91f added paging for PromptWidget output
fixed disAsm of graphic bits
2023-03-19 10:46:21 +01:00
Thomas Jentzsch 55099ecbdd trying to address #962 for Linus & MacOS 2023-03-18 21:06:06 +01:00
Thomas Jentzsch fc3b983080 added alternative theme, switchable via hotkey. this is a preparation for SDL2 supporting system theme change events (day/night) soon 2023-03-15 17:06:52 +01:00
Thomas Jentzsch 3faefe7c46 minor fixes to debugger cart info 2023-03-15 16:46:43 +01:00
Thomas Jentzsch 492fce7645 added missing changed class 2023-03-15 14:44:01 +01:00
Thomas Jentzsch 22fd81aa7d fixed odd ROM sizes for 3E+ (fixed #960 2023-03-15 13:57:30 +01:00
Thomas Jentzsch 3a389752bd catch exception in BSPF::stoi (fixes #958) 2023-02-27 19:43:23 +01:00
Stephen Anthony bda42c3236 Some fixes for warnings from cppcheck. 2023-02-18 15:33:28 -03:30
Stephen Anthony dd3d18ce8a Attempt to fix macOS automated builds. 2023-02-16 17:57:30 -03:30
Thomas Jentzsch f6087efe92 fixed right controller detection for Maze Craze 2023-02-16 19:20:16 +01:00
Thomas Jentzsch 38d790b552 enhanced PlusROM dialog to show device id 2023-02-08 09:50:36 +01:00
Stephen Anthony 24942e2c20 Fix minor spelling mistake; there are no castrated goats here :) 2023-01-29 12:17:48 -03:30
Thomas Jentzsch 38c45e0fee added "code in RAM" execution check for F4SC, F6SC and F8SC (addresses #933) 2023-01-29 12:55:03 +01:00
Thomas Jentzsch a3c862900d minor fix for unwind/rewind display string 2023-01-29 10:01:38 +01:00
Stephen Anthony e7b0fcc45c Fix missing const caught by clang-tidy. 2023-01-28 19:22:31 -03:30
Thomas Jentzsch 4d8d30bd96 added two missing debugger save states 2023-01-28 10:22:07 +01:00
Stephen Anthony 336a0bf22a A few items I forgot in the last commit. 2023-01-26 17:04:05 -03:30
Stephen Anthony e21a0400f4 Further optimization to FSNodeWINDOWS; eliminate function call. 2023-01-26 16:44:16 -03:30
Thomas Jentzsch 1f2e9bbb28 fixed jittering driving controller when using keyboard 2023-01-25 17:02:48 +01:00
Thomas Jentzsch 74a3b42903 re-enabled mouse and Stelladaptor input for Driving Controller (fixes #951) 2023-01-18 17:01:21 +01:00
Thomas Jentzsch 9c16cccdef Another attempt to fix #931 in a good way. 2023-01-17 23:04:52 +01:00
Thomas Jentzsch 8a4d629061 Merge branch 'master' of https://github.com/stella-emu/stella 2023-01-17 16:29:23 +01:00
Thomas Jentzsch 27f1968ef6 stop disassembling at areas marked as ROW (fixes #931) 2023-01-17 16:29:11 +01:00
Stephen Anthony af526c0288 Small optimization; don't unnecessarily clear buffers. 2023-01-08 21:52:24 -03:30
Stephen Anthony ada36cd3d7 Fix Xcode project after recent refactoring. 2023-01-06 11:38:34 -03:30
Thomas Jentzsch db75df51b4 improved driving controller responsiveness to digital input 2023-01-06 00:43:38 +01:00
Thomas Jentzsch ec982482aa fixed saving driving controller mappings 2023-01-05 22:21:15 +01:00
Thomas Jentzsch 7779dea09b fixed Joy2B+ code for libretro 2023-01-05 08:37:48 +01:00
hunterk 18afccf2b8 add Joy2B+ support to libretro (#950)
fixes #949 and returns input to Elevator Agent game
2023-01-05 08:33:14 +01:00
Stephen Anthony 6e1bc4c77c Fix compile error in clang-16; large number of constexpr string_view causes compile error. 2022-12-30 21:17:02 -03:30
Stephen Anthony c51b372a53 Updated httplib, libpng and sqlite libs to latest releases. 2022-12-30 19:56:45 -03:30
Stephen Anthony a0ee07fdc3 Remove FIXME for string_view conversion. 2022-12-30 18:34:12 -03:30
Stephen Anthony bdffdd7b9d Minor string optimizations. 2022-12-30 18:00:37 -03:30
Stephen Anthony ca59a8f3c8 Updated files to 2023; an early Happy New Year to anyone reading this logs. 2022-12-30 14:11:04 -03:30
Stephen Anthony e2fc5010bf Updated UNIX config files to latest version. 2022-12-30 14:08:34 -03:30
Stephen Anthony 61f8e202e7 Minor formatting fixes. 2022-12-29 20:03:24 -03:30
Stephen Anthony 1252d1da94 Another string_view conversion. 2022-12-29 15:22:38 -03:30
Stephen Anthony c81bdf642b Convert MD5 functionality to proper C++17 class. 2022-12-29 12:25:39 -03:30
Stephen Anthony d5f77514ab Various fixes for suggestions from clang-16. 2022-12-29 10:19:14 -03:30
Stephen Anthony 5efaebca76 Remove std::stoi completely; reimplement with std::from_chars and string_view. 2022-12-28 20:57:31 -03:30
Thomas Jentzsch 200caa8423 Merge branch 'master' of https://github.com/stella-emu/stella 2022-12-28 14:12:42 +01:00
Thomas Jentzsch 3a5ec79227 Added images processing files (Windows only) 2022-12-28 14:12:23 +01:00
Stephen Anthony c2a80ada0e Add experimental 'mold' linker support to configure for UNIX. 2022-12-27 10:58:01 -03:30
Thomas Jentzsch ba5630e50b updated doc for new high score game support 2022-12-25 10:14:41 +01:00
Thomas Jentzsch 204a865da4 added some more high score properties (resolves #929) 2022-12-25 10:07:51 +01:00
Stephen Anthony 301f20889e Consolidate and refactor some code (mostly string conversions). 2022-12-24 16:42:08 -03:30
Stephen Anthony 217f52822d Fix potential crash on empty string. 2022-12-24 13:21:13 -03:30
Stephen Anthony d428c6ac9a More conversions to string_view. 2022-12-23 20:01:24 -03:30
Thomas Jentzsch 2dba71290d reworked RiotWidget 2022-12-22 14:25:05 +01:00
Stephen Anthony 64ed418bb5 And a few more string_view conversions. 2022-12-21 20:36:35 -03:30
Stephen Anthony 02d7b85fd9 Yet more conversion of 'const char*' to string_view. 2022-12-21 20:20:30 -03:30
Stephen Anthony eaca65d452 More conversion of 'const char*' to string_view. 2022-12-21 19:24:37 -03:30
Thomas Jentzsch 8637c11338 reworked TIAWidget 2022-12-21 18:59:12 +01:00
Stephen Anthony e407fd9d17 Eliminate redundant checks for empty strings. 2022-12-21 12:25:40 -03:30
Stephen Anthony 7c3200500e Improve Bankswitch class efficiency by using string_view. 2022-12-20 22:16:11 -03:30
Thomas Jentzsch b382878d0e fixed two bugs regarding Joy2B+ controller 2022-12-20 11:07:53 +01:00
Stephen Anthony 06699aafa0 Yet more conversion of 'const string&' to 'string_view'. 2022-12-19 19:33:19 -03:30
Stephen Anthony e2534af4e8 Updated changelog. 2022-12-19 17:24:08 -03:30
Stephen Anthony 50a2823da6 More conversion of 'const string&' to 'string_view'. 2022-12-19 17:21:36 -03:30
Thomas Jentzsch 1966a9b805 enhanced missile state display in debugger
updated 3E+ comments
2022-12-19 11:38:43 +01:00
Stephen Anthony 8c7d8931f2 Default to using system-wide libsqlite3 on Linux/UNIX systems.
Fix for slow exit from app in this mode is now fixed.
2022-12-18 21:18:56 -03:30
Thomas Jentzsch 80d0db751f fixed messages lost when changing state with auto pause enabled (fixes #944) 2022-12-17 11:03:48 +01:00
Stephen Anthony 859dacdf63 Convert 'const string&' to 'string_view', as per C++17 recommendations. WIP. 2022-12-16 19:15:30 -03:30
Thomas Jentzsch bc12f241e5 minor UI update to Power-on options dialog 2022-12-16 09:07:18 +01:00
Thomas Jentzsch 262c2c18f7 3e+ comments fixed 2022-12-14 18:15:27 +01:00
Stephen Anthony fef3437579 Restrict RAM searching to hex values only. 2022-12-11 15:50:40 -03:30
Thomas Jentzsch 8ca1fc5ad5 added middle mouse button support (emulates double click) 2022-12-06 19:21:07 +01:00
Stephen Anthony 3e23e2f8bf Updated zlib to latest version (1.2.13). 2022-12-04 20:42:14 -03:30
Stephen Anthony 2cdb52d1fa Some refactoring in ZipHandler. Debugging code present for now. 2022-12-04 18:38:43 -03:30
Thomas Jentzsch 3370ca4afc fixed multi segment cart disassembly 2022-12-04 18:15:11 +01:00
Thomas Jentzsch e9efdbc3a1 slightly optimized Thumb emulation for R77 2022-12-03 00:38:31 +01:00
Thomas Jentzsch f677acf273 and some more (forgot to save) 2022-12-02 19:52:03 +01:00
Thomas Jentzsch e5bb3c9ff8 some code cleanup 2022-12-02 19:51:24 +01:00
Stephen Anthony 2efbca4ef8 Disable warning for deadcode in Thumbulator. 2022-12-02 12:20:36 -03:30
Thomas Jentzsch 6e86a2472f added Release PGO x64 build configuration for VS 2022-12-02 10:42:21 +01:00
Stephen Anthony d02f06e6a3 Convert more defines to static constexpr, take 2. 2022-12-01 19:13:44 -03:30
Stephen Anthony 746619a177 Revert "Convert more defines to static constexpr."
This reverts commit 62ad70bed5.

Mistakenly checked in debug code for another part of the codebase.
2022-12-01 19:08:27 -03:30
Stephen Anthony 62ad70bed5 Convert more defines to static constexpr. 2022-12-01 19:04:01 -03:30
Stephen Anthony 2761ffa793 Fix missing braces on switch/case block. 2022-12-01 18:46:53 -03:30
Stephen Anthony 36c0457cb3 Convert defines to static constexpr. 2022-12-01 18:31:31 -03:30
Stephen Anthony 380169f23c Implemented suggestions from clang-tidy-16 (mostly emplace vs. push_back). 2022-12-01 15:39:21 -03:30
Thomas Jentzsch a0787d92da added some ARM ROMs for profiling 2022-11-30 15:09:33 +01:00
Thomas Jentzsch 6293372122 added a few more FORCE_INLINE and inline hints 2022-11-30 09:33:04 +01:00
Thomas Jentzsch 05679d604e next try 2022-11-29 16:44:47 +01:00
Thomas Jentzsch 51f8d904d2 Revert "improved inlining in VS (I hope this doesn't break the code again)"
This reverts commit 46f2b6aac0.
2022-11-29 16:10:43 +01:00
Thomas Jentzsch 46f2b6aac0 improved inlining in VS (I hope this doesn't break the code again) 2022-11-29 14:07:51 +01:00
Christian Speckner 1bbcd07da0 Fix build. 2022-11-29 12:18:38 +01:00
Thomas Jentzsch 752b779699 trying to fix build errors 2022-11-29 11:12:08 +01:00
Thomas Jentzsch ceb3ba9fd3 accelerated emulation by using forced inlines 2022-11-29 10:53:31 +01:00
Thomas Jentzsch 7febd63f99 added global FORCE_INLINE macro
used FORCE_INLINE macro in Thumbulator
2022-11-29 09:23:39 +01:00
Thomas Jentzsch 06934fa8d0 optimized thumb flags handling 2022-11-28 22:12:48 +01:00
Thomas Jentzsch 4c09d07e07 Merge branch 'master' of https://github.com/stella-emu/stella 2022-11-27 13:10:22 +01:00
Thomas Jentzsch 2bfb885e87 optimized thumb branch instructions 2022-11-27 13:10:02 +01:00
Stephen Anthony 75c6efbe9c Update Linux build script. 2022-11-24 16:04:15 -03:30
Stephen Anthony 9bf2373e71 Make automated builds use latest SDL (2.26) where possible. 2022-11-24 15:35:09 -03:30
Thomas Jentzsch 4a62657cd3 fixed 7800 pause button 2022-11-23 22:29:43 +01:00
Stephen Anthony 62f48dc662 Updates to Xcode project for Xcode 14. 2022-11-23 15:27:11 -03:30
Stephen Anthony c48d878a20 Updated to latest sqlite3 release. 2022-11-20 15:31:26 -03:30
Stephen Anthony 78a6b00dde Fix typo. 2022-11-17 15:36:35 -03:30
Stephen Anthony 074c169c8c More 'const char* const' fixes. 2022-11-13 12:31:36 -03:30
Stephen Anthony 26610f44d9 Minor fixes to FSNodePOSIX. 2022-11-12 21:44:50 -03:30
Stephen Anthony 5748de3833 Use already calculated file size, and cache for later use. 2022-11-11 20:26:14 -03:30
Stephen Anthony 4f39859c49 Stop WAV playing when exiting a KidVid ROM and starting a non-KidVid one. 2022-11-03 21:42:14 -02:30
Stephen Anthony 885b5e971a Yet more cleanups in FSNodeWINDOWS. 2022-10-29 16:12:39 -02:30
Thomas Jentzsch d8b2877649 added VSYNC warning to console info overlay in developer mode 2022-10-20 12:48:51 +02:00
Stephen Anthony 3337086601 Speed up file/directory access in Windows by 3-4x. 2022-10-18 17:21:13 -02:30
Stephen Anthony 4302488754 More cleanups to FSNodeWINDOWS. 2022-10-15 19:54:51 -02:30
Stephen Kitt f05aeb3e46 Use apt-get instead of apt (#938)
This avoids warnings about apt's suitability for use in scripts.

Signed-off-by: Stephen Kitt <steve@sk2.org>

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-10-13 09:31:14 -02:30
Stephen Kitt db185d326c Upgrade GHAs to drop save-state and set-output (#939)
This bumps actions/checkout to v3.1.0 and microsoft/setup-msbuild to
v1.1.3, which switch to environment files. See
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
for context and
https://github.com/actions/checkout/releases/tag/v3.1.0 and
https://github.com/microsoft/setup-msbuild/releases/tag/v1.1.3 for
details of the changes.

Signed-off-by: Stephen Kitt <steve@sk2.org>

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-10-13 11:26:37 +02:00
Stephen Anthony 65e4959a75 More cleanups to FSNodeWINDOWS. 2022-10-12 18:45:24 -02:30
Thomas Jentzsch 7914f4a1b3 fixed build test 2022-10-12 22:21:10 +02:00
Thomas Jentzsch ecfc678a18 failed build test 2022-10-12 22:03:48 +02:00
Stephen Anthony 38dc5173ec More cleanups to FSNodePOSIX. 2022-10-12 12:58:00 -02:30
Stephen Anthony 93df53e751 Add missing directory separator that sometimes is missing in SQL database file. 2022-10-11 18:45:46 -02:30
Stephen Anthony 4ef65aa88b Remove Readme.txt, replace with README.md (which contains the former). 2022-10-10 23:33:51 -02:30
Stephen Anthony d6f1973688 Remove appveyor script; we can always re-enable if required. 2022-10-10 23:28:33 -02:30
Stephen Kitt 963c7866dc Run the build GHA on pushes as well as PRs (#937)
This ensures that commits get a checkmark if they pass all tests.

Signed-off-by: Stephen Kitt <steve@sk2.org>

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-10-10 18:33:56 -02:30
Stephen Anthony f6762cb96d Some optimizations for FSNodeWINDOWS. 2022-10-10 18:26:45 -02:30
Stephen Anthony ae5b448478 More optimization for FSNodePOSIX. 2022-10-10 17:05:22 -02:30
Stephen Anthony 75f93c566b Some minor optimizations to FSNodePOSIX. 2022-10-10 16:40:25 -02:30
Stephen Kitt 2d7aa7cbb8 Add a GitHub action to build on Windows (#936)
This reproduces the Appveyor build for 32- and 64-bit Windows.

Signed-off-by: Stephen Kitt <steve@sk2.org>

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-10-10 15:28:03 -02:30
Stephen Kitt 8ff021d1f8 Add a GitHub action to build on Linux and macOS (#935)
As with Travis CI, the test is only deemed successful on each platform
if the Stella build completes successfully.

For Linux, the test runs on Ubuntu with the toolchain test build
repository, using G++ 9, and the packaged version of SDL2, which is
guaranteed to be at least 2.0.10.

For macOS, SDL2 2.0.10 is still built from the upstream source code;
however that no longer builds with the newer Xcode versions available
in GHAs, so the build now uses "Unix-style" ./configure && make.

The runners provide two cores on Linux and three cores on macOS, so
the compile stages use the appropriate -j setting to build in
parallel.

Signed-off-by: Stephen Kitt <steve@sk2.org>

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-10-10 14:45:55 -02:30
Stephen Anthony dc888cf888 Fix minor warning from clang-tidy. 2022-10-09 21:50:57 -02:30
Stephen Anthony 031eb78fd8 Separate sound mute and enable functionality.
Mute simply changes the sound level; disabling sound completely is now done separately.
2022-10-09 21:28:35 -02:30
Thomas Jentzsch 44161326ad updated debugger doc for timers (screenshots) 2022-10-09 15:00:29 +02:00
Thomas Jentzsch 7736d65c84 fixed jitter emulation 2022-10-09 12:15:01 +02:00
Thomas Jentzsch bd51fbdac5 fixed frame layout detection 2022-10-09 07:38:08 +02:00
Stephen Anthony 7fd7f4df10 Updated sqlite3 to latest version. 2022-10-08 23:26:12 -02:30
Stephen Anthony ae75b94f23 Updated httplib to latest version. 2022-10-08 22:26:35 -02:30
Stephen Anthony 3ed08681ef Updated PNG lib to latest version. 2022-10-08 22:22:48 -02:30
Stephen Anthony c8192955b3 Updated JSON lib to latest version. 2022-10-08 22:15:53 -02:30
Stephen Anthony edc82b3888 Suggested fixes from clang-tidy. 2022-10-08 20:33:59 -02:30
Stephen Anthony 27f84976da Fix minor warning: parameter mirrors instance variables. 2022-10-08 20:11:31 -02:30
Thomas Jentzsch 5f1d6ee028 reworked timer syntax and code and fixed some bugs 2022-10-08 11:54:38 +02:00
Thomas Jentzsch 13e74507cb Merge branch 'master' of https://github.com/stella-emu/stella 2022-10-07 09:29:18 +02:00
Thomas Jentzsch 9b62b15637 fixed launcher image navigation for HiDPI mode 2022-10-07 09:29:02 +02:00
Stephen Anthony ce533245cf Add new class to Xcode project. 2022-10-06 13:20:53 -02:30
Stephen Anthony 64bcd660b2 Fix minor compile issues. 2022-10-06 13:07:27 -02:30
Thomas Jentzsch 9406bc7c6b ...plus a fix for the make file 2022-10-06 17:07:11 +02:00
Thomas Jentzsch 8682b5bda0 Merge branch 'master' of https://github.com/stella-emu/stella 2022-10-06 17:04:40 +02:00
Thomas Jentzsch ad8e5eb3f7 ...and the usual missing new files 2022-10-06 17:04:12 +02:00
Stephen Anthony 2a6fdcdb3d Fixed typo in module.mk. 2022-10-06 12:33:45 -02:30
Thomas Jentzsch 7a39ca8b6e added user defined timers to debugger (TODO: screenshots) 2022-10-06 16:55:00 +02:00
Thomas Jentzsch 7655f7cd8a Fixed "logBreaks" output in debugger 2022-10-03 18:16:14 +02:00
Stephen Anthony 79efea994a Some refactoring of SoundSDL2, placing WAV handling in its own inner class. 2022-10-01 21:06:12 -02:30
Thomas Jentzsch d6acadc329 fixed unwanted button up events in UI navigation 2022-10-01 21:21:20 +02:00
Thomas Jentzsch aebc097e95 enhanced UI navigation with a controller
added "Cancel" option to LauncherDialog context menu if opened with a controller
updated docs for image navigation in LauncherDialog
2022-10-01 11:07:02 +02:00
Stephen Anthony 72c6e69bf0 First pass at separating Sound mute/pause functionality.
This will need lots of testing, since it touches many parts of the code.
2022-09-24 21:33:39 -02:30
Stephen Anthony f98fef11db Fixed crash in resampling WAV playing; forgot to create an array.
Make WAV resampling default behaviour.
2022-09-19 01:33:36 -02:30
Stephen Anthony b927f214f3 Use unique_ptr instead of C-style allocations. 2022-09-18 16:56:57 -02:30
Thomas Jentzsch d0c94e5e14 eliminated frequent memory allocation while playing WAV files 2022-09-16 15:18:24 +02:00
Thomas Jentzsch ce684daacc fixed WAV echo problem and enabled on-the-fly resampling 2022-09-15 18:34:37 +02:00
Thomas Jentzsch 26d6f0db69 added on-the-fly WAV resampling (disabled, causes echo) 2022-09-15 15:21:10 +02:00
Thomas Jentzsch 37f8a5595f removed debug code and cast warning 2022-09-14 19:34:30 +02:00
Thomas Jentzsch af5272cff4 fixed interrupted WAV continuing to play at restart 2022-09-14 17:38:47 +02:00
Thomas Jentzsch 077366f34b fixed Sound muting for WAV files 2022-09-14 13:39:24 +02:00
Stephen Anthony 2208460aee More 'const' conversion, with help from clang-15. 2022-09-13 22:52:59 -02:30
Thomas Jentzsch 0330545769 implemented gapless playback for WAV files (KidVid) 2022-09-13 15:24:19 +02:00
Thomas Jentzsch 67a55e5769 added messages for Kid Vid 2022-09-10 15:56:25 +02:00
Thomas Jentzsch ca2542d3a1 added mute all songs option for Kid Vid 2022-09-09 14:09:46 +02:00
Stephen Anthony 8978295e84 Eliminate unused variable. 2022-09-08 22:59:11 -02:30
Stephen Anthony 397d7a003e Update appveyor Windows CI builds to use latest SDL. 2022-09-08 22:08:39 -02:30
Thomas Jentzsch a77569d1e5 enhanced KidVid to allow selecting and starting the games via console switches 2022-09-08 19:43:58 +02:00
Thomas Jentzsch 35bebad0f8 fixed cut off Kid Vid songs 2022-09-07 12:26:03 +02:00
Thomas Jentzsch 40c77bba71 minor Kid Vid doc update 2022-09-06 08:56:56 +02:00
Thomas Jentzsch 0d5bc7e7ac enhanced KidVid song skipping
removed clicks at end of songs
2022-09-05 23:15:21 +02:00
Stephen Anthony fb0736b2e0 Bumped state number for changes to KidVid state file. 2022-09-04 14:31:15 -02:30
Thomas Jentzsch 4f1b1ab97e refactored KidVid code a bit
updated doc
2022-09-04 18:40:46 +02:00
Stephen Anthony 87eee88752 Bump state version for KidVid; clean up some typos. 2022-09-04 12:55:53 -02:30
Thomas Jentzsch 497cf09a98 added KidVid tape state serializing 2022-09-04 10:03:40 +02:00
Thomas Jentzsch cd147492be updated doc for Kid Vid 2022-09-04 08:48:19 +02:00
Stephen Anthony f753d47c71 Add stubs to KidVid for save/load functionality (TODO). 2022-09-03 22:43:42 -02:30
Stephen Anthony 6924a3d159 Minor formatting cleanups for recent commits. 2022-09-03 20:10:22 -02:30
Thomas Jentzsch c7cac63a38 added WAV file volume adjustment (resolves #77) 2022-09-03 20:56:38 +02:00
Stephen Anthony d54e7f34fe Fix a few minor compiler warnings.
Make WAV play methods not pure virtual, so we can change them without affecting libretro.
2022-09-03 14:51:20 -02:30
Stephen Anthony 574b60588b libretro: Fix compile failure from latest Sound changes. 2022-09-03 14:08:09 -02:30
Stephen Anthony 287a035440 Fix minor compile warning. 2022-09-03 13:13:29 -02:30
Thomas Jentzsch 9b1238464e added WAV playing and adapted KidVid code accordingly 2022-09-03 16:54:33 +02:00
Stephen Anthony 8e246e200c Convert KidVid file I/O to C++ ifstreams. 2022-09-02 10:14:14 -02:30
Thomas Jentzsch d0fad1091a some KidVid refactoring 2022-09-02 08:18:55 +02:00
Stephen Anthony 74c0613147 One last fix for Xcode project. 2022-09-01 15:24:37 -02:30
Stephen Anthony 02a8970bb6 Finally fixed Xcode project. 2022-09-01 15:07:57 -02:30
Stephen Anthony 5f0ded46ce More fixes to Xcode project. 2022-09-01 14:12:52 -02:30
Thomas Jentzsch 371c369ae4 Merge branch 'master' of https://github.com/stella-emu/stella 2022-09-01 17:47:35 +02:00
Thomas Jentzsch 59c1b21b01 allow playing KidVid without tapes 2022-09-01 17:47:19 +02:00
Stephen Anthony b8812d7b6b Second pass at fixing Xcode project. 2022-09-01 13:05:26 -02:30
Stephen Anthony c8b3bd8ba0 First pass at fixing Xcode project. 2022-09-01 12:52:03 -02:30
Stephen Anthony 99d81cc58c Test commit from my Mac. 2022-09-01 12:19:47 -02:30
Thomas Jentzsch 98b06cffc0 reworked KidVid code a little bit (still not working) 2022-09-01 13:58:43 +02:00
Stephen Anthony d6c1481d17 Fix minor initialization warning. 2022-08-25 20:57:57 -02:30
Thomas Jentzsch 4b79864ccc disabled random start bank for MDM bankswitching ROMs 2022-08-22 09:36:38 +02:00
Thomas Jentzsch 21f1154c07 fixed multiple images crash when no images exist 2022-08-22 09:35:53 +02:00
Stephen Anthony 9179a5b1f0 Fix minor warning with g++ and tinyexif. 2022-08-21 19:42:37 -02:30
Stephen Anthony 2048c8f2a6 Final batch of fixes from clang-tidy (for now). 2022-08-21 19:33:08 -02:30
webgeek1234 af50ea273c libretro: android: Fix jni source paths (#921)
Change-Id: Ic580fee9833b4110ddcead0033e8106871b22241
2022-08-21 21:14:15 +02:00
Stephen Anthony 109d36a1c2 Second pass at fixes for suggestions from clang-tidy. 2022-08-21 13:53:52 -02:30
Thomas Jentzsch 3e59afb4cf added alternative debugger snapshot naming option 2022-08-21 12:49:13 +02:00
Stephen Anthony 7f86868cbe Merge branch 'master' of github.com:stella-emu/stella 2022-08-20 15:32:45 -02:30
Stephen Anthony 84a63da5da Yay, got clang-tidy working again. First pass at fixing suggestions. 2022-08-20 15:32:15 -02:30
Thomas Jentzsch 85c6172224 Merge branch 'master' of https://github.com/stella-emu/stella 2022-08-20 20:00:27 +02:00
Thomas Jentzsch 72a4254272 added "swchb" command to debugger 2022-08-20 20:00:03 +02:00
Stephen Anthony 4dfdc1b0f8 libretro: Second pass at fixing Android builds. 2022-08-19 18:40:42 -02:30
Stephen Anthony 8063a3dacd libretro: Attempt to fix Android build script. 2022-08-19 16:05:55 -02:30
Stephen Anthony 17a29dec98 Update .gitignore for recent directory changes. 2022-08-19 15:26:17 -02:30
Thomas Jentzsch 2a6adb536e made image area in Launcher a square to allow better display of vertical oriented images (e.g. boxes)
changed unused image area background to black
2022-08-19 10:23:34 +02:00
Stephen Anthony a117ebd31e Fixed a few new paths missed in previous commits. 2022-08-18 19:15:28 -02:30
Stephen Anthony ec7d93b065 Fix Windows auto-builds. 2022-08-18 19:06:18 -02:30
Thomas Jentzsch df59607b4d updated .gitignore for reorganized folders 2022-08-18 21:46:16 +02:00
Thomas Jentzsch 66dbd35807 fixed paths for Libretro 2022-08-18 21:40:21 +02:00
Thomas Jentzsch 4fdf485020 updated doc for reordered launcher top widgets 2022-08-18 20:03:48 +02:00
Thomas Jentzsch ded7982835 enhanced multiple image sorting
improved image memory allocation
2022-08-18 16:31:54 +02:00
Stephen Anthony c3586060df More rearrangements of classes in Visual Studio project file.
Some fixes for suggestions from VS.
2022-08-17 19:11:41 -02:30
Stephen Anthony 53fd31408f Remove debugging code. 2022-08-17 18:30:27 -02:30
Thomas Jentzsch 2ae4cc49e4 removed a debug cerr 2022-08-17 20:36:26 +02:00
Thomas Jentzsch 2b37ae9ca6 two small fixes 2022-08-17 20:32:49 +02:00
Stephen Anthony 0184fc34d2 Placed all debugger gui files in `src/debugger/gui` in Visual Studio. 2022-08-17 12:54:24 -02:30
Stephen Anthony 1c42ef7ebb Fix `yacc` directory in Visual Studio. 2022-08-17 12:45:22 -02:30
Stephen Anthony 633735e085 Move `yacc` directory to `src/debugger`. 2022-08-17 12:38:40 -02:30
Stephen Anthony b7722796a5 Fix Visual Studio project file for `src/lib` reorg. 2022-08-17 12:16:09 -02:30
Stephen Anthony 9a04d5275f Move various libs to `src/lib`. Again, expect some breakage. 2022-08-17 11:41:31 -02:30
Stephen Anthony 83a7337bc5 Fix paths in Windows build script. 2022-08-17 11:16:20 -02:30
Stephen Anthony cfaf737e92 First pass at moving platform-specific code to src/os.
Likely there *will* be breakage.
2022-08-17 10:50:57 -02:30
Stephen Anthony 7c5ab476da Fixed segfault; reference to string was removed after it was assigned. 2022-08-17 09:40:13 -02:30
Stephen Anthony af728db149 Fix tinyexif in Visual Studio. 2022-08-17 08:05:42 -02:30
Stephen Anthony 241ee4803e Fixed tinyexif in Linux. Now to fix it in Windows. 2022-08-17 07:48:27 -02:30
Thomas Jentzsch 7b7cf84594 updated doc for multiple images format 2022-08-17 10:46:50 +02:00
Thomas Jentzsch 93beb78754 added reading EXIF from JPG images 2022-08-17 10:08:57 +02:00
Thomas Jentzsch a57ca5edc1 made ROM info delay adaptive
some cleanup of the new JPG reading code
2022-08-17 09:17:04 +02:00
Stephen Anthony be5ea25619 Fix nanojpeg in Visual Studio. 2022-08-16 21:57:57 -02:30
Stephen Anthony bba721375d Second pass at JPG support. nanojpeg *really* doesn't like being split into h/c files. 2022-08-16 21:45:19 -02:30
Stephen Anthony 5598490601 Fix PNG/JPG loading in Linux. 2022-08-16 21:20:09 -02:30
Thomas Jentzsch 81bc5188f5 and the usual, missing update of the .mk file 2022-08-16 22:11:40 +02:00
Thomas Jentzsch a54163dbf7 the usual, forgotten new files 2022-08-16 22:08:40 +02:00
Thomas Jentzsch 576f1cb6fe Merge branch 'master' of https://github.com/stella-emu/stella 2022-08-16 22:07:35 +02:00
Thomas Jentzsch c9ea1aa791 added JPG loading support 2022-08-16 22:03:06 +02:00
Stephen Anthony a9e63c1349 Fix minor compile warning in g++. 2022-08-16 14:05:33 -02:30
Stephen Anthony 2998131b74 Updated Xcode build for missing class. 2022-08-15 14:22:43 -02:30
Thomas Jentzsch 6d0cb6d458 updated doc for multiple launcher images (TODO: R77) 2022-08-15 14:12:07 +02:00
Stephen Anthony ea84f0a194 libretro: Clean up redundant cxx files. 2022-08-14 20:25:41 -02:30
Thomas Jentzsch 1a309235b8 improved pending rom update handling
added using a regular expression for searching images
2022-08-14 15:22:40 +02:00
Stephen Anthony df2330989d We don't need to check for directory, since we're using FSNode::ListMode::FilesOnly. 2022-08-13 21:24:03 -02:30
Thomas Jentzsch 82a5106b85 added multiple image searching delay 2022-08-14 00:53:03 +02:00
Stephen Anthony 65c5498cda Fix compile error under g++. 2022-08-13 17:22:02 -02:30
Thomas Jentzsch f2e465c969 optimized image filter filter 2022-08-13 21:17:55 +02:00
Thomas Jentzsch 7810b9f575 and some more fixes 2022-08-13 15:12:41 +02:00
Thomas Jentzsch 76659c10de some fixes and cleanup 2022-08-13 10:09:44 +02:00
Stephen Anthony 4b73c9486c Fix compile error in Linux. 2022-08-12 16:43:01 -02:30
Thomas Jentzsch 9355ac7fc9 fixed reversed image directions 2022-08-12 20:52:25 +02:00
Thomas Jentzsch eb1fe32c0a updated make file for new class 2022-08-12 20:47:31 +02:00
Thomas Jentzsch c648706e82 Merge remote-tracking branch 'remotes/origin/feature/multiimages' 2022-08-12 20:45:28 +02:00
Thomas Jentzsch c43c6ad5be added image navigation display
added keyboard image navigation (TODO: controller)
2022-08-12 20:12:10 +02:00
Thomas Jentzsch 7590b9bad2 added reading and displaying image labels 2022-08-12 11:40:21 +02:00
Thomas Jentzsch 1883c5ab58 added multiple image searching and switching 2022-08-10 20:59:02 +02:00
Thomas Jentzsch 59fe1888c4 preparing for #916 2022-08-10 08:19:12 +02:00
Stephen Anthony c9181e5add Some fixes for suggestions from cppcheck. 2022-08-09 14:34:53 -02:30
Thomas Jentzsch 731432d676 a few minor changes (finally resolves #913 and #914) 2022-08-06 09:20:13 +02:00
Thomas Jentzsch 70daa0868a added bankswitching type to displayed multi cart information 2022-08-05 18:57:11 +02:00
Stephen Anthony 999f9bfd5b Implemented suggestions from various linting tools. 2022-08-04 22:15:04 -02:30
Stephen Anthony 25dd887283 Fixed compile error. 2022-08-04 18:38:10 -02:30
Thomas Jentzsch 6f5d4e3fff added disabling of some Game properties widgets for multi carts
added ROM name to Game properties title
2022-08-04 22:56:12 +02:00
Thomas Jentzsch 809119ff46 Update README.md 2022-08-02 15:51:02 +02:00
Thomas Jentzsch 2697c7bd47 Update README.md 2022-08-02 15:50:23 +02:00
Thomas Jentzsch e88797253e Update README.md 2022-08-02 15:47:16 +02:00
Thomas Jentzsch 0ef63d4b79 Update README.md 2022-08-02 15:44:38 +02:00
Thomas Jentzsch 78e859725e updated doc for optional filtering of Game Properties/Emulation/Types using ROM size 2022-08-02 12:33:14 +02:00
Thomas Jentzsch 5e4a8b66d3 added optional filtering of Game Properties/Emulation/Types using ROM size (TODO: doc) 2022-07-30 21:24:39 +02:00
Thomas Jentzsch a6746103ec added if loading by ROM property name fails, try ROM file name (fixes #911) 2022-07-15 11:11:56 +02:00
Thomas Jentzsch 87da2de653 enhanced scanline based frame layout detection to fractional values, this allows combining results with color based layout overruling 2022-07-14 20:03:45 +02:00
Stephen Anthony bc5aaac936 Fix minor compile warnings. 2022-07-13 11:32:27 -02:30
Thomas Jentzsch ffec4ea576 added optional autodetection of PAL-60 & NTSC-50 2022-07-13 10:34:15 +02:00
Thomas Jentzsch 2ca38d65bb improved Windows command line output 2022-07-07 21:29:38 +02:00
Thomas Jentzsch a1f6194c53 fixed console output not working under Windows 2022-07-07 20:25:30 +02:00
Thomas Jentzsch b8527cd5ef Some minor polishing on LauncherDialog 2022-07-05 11:45:17 +02:00
Thomas Jentzsch 5b736d13d9 Revert "Doubled gap before "Filter" label"
This reverts commit 84c391e17d.
2022-07-05 09:23:09 +02:00
Thomas Jentzsch 84c391e17d Doubled gap before "Filter" label 2022-07-05 09:18:14 +02:00
splendidnut 526544e355 Suggested layout changes for the Launcher UI. (#910)
* Changed the layout in the new Launcher UI to have the controls in a more natural order.

* Changed the layout using provided feedback in the Github pull-request.
- Swapped button locations for Options and Help.
- Moved Reload button to be left of the Filter label/field.
- Updated screenshots in docs directory

* Updated screenshots in docs directory to show Favorites folder in file listing.

Co-authored-by: splendidnut <pblackman@gmail.com>
2022-07-05 08:48:26 +02:00
Thomas Jentzsch cd129decfc updated PathWidget to skip reloading if path has not changed 2022-07-02 20:59:33 +02:00
Stephen Anthony 5b3c4eb2d1 Fix warnings in gcc and clang for missing initializers.
Normally I would disable the warning completely (everywhere), but it's very useful to have.
In this case, the code can be much faster, as it saves having to initialize empty string objects.  So we disable the warning selectively.
2022-07-01 10:05:35 -02:30
Thomas Jentzsch a5d79817ef removed superfluous empty initializers
made InputDialog slightly wider
2022-07-01 10:27:17 +02:00
Thomas Jentzsch fd3915af18 Compacted controller mappings doc 2022-07-01 10:00:26 +02:00
Stephen Anthony 4c243b6738 Added Joy2B classes to Xcode project. 2022-06-30 13:25:07 -02:30
Thomas Jentzsch 0a81ecc574 oops 2022-06-30 16:43:54 +02:00
Thomas Jentzsch c7f4dacc69 Merge branch 'master' of https://github.com/stella-emu/stella 2022-06-30 16:33:07 +02:00
Thomas Jentzsch e0c1aecfc3 fixed filename of Joy2BPlusWidget 2022-06-30 16:32:53 +02:00
Stephen Anthony 358140dbf4 Fix compilation in Linux (module.mk incorrect). 2022-06-30 08:53:18 -02:30
Thomas Jentzsch 37c090d649 added Joy 2B+ support (resolves #909) 2022-06-30 12:54:12 +02:00
Thomas Jentzsch ec2b531f45 enhanced keyboard controller detection (except MagiCard) (fixes #908) 2022-06-29 23:40:13 +02:00
Thomas Jentzsch 192897354d 7800 pause is now working again (fixes #905)
updated doc for 7800 pause hotkey
2022-06-26 19:39:18 +02:00
Stephen Anthony 40206d8af8 libretro: disable TV jitter until it settings are exposed through the UI.
This fixes rolling on NTSC ROMs that worked previous to 6.7 release.
2022-06-18 18:09:06 -02:30
Stephen Kitt 70d15a5629 Add Terminus font licensing information (#902)
src/gui/Stella*tFont.hxx are derived from the Terminus font, whose
license requires the full copyright notice and license to be provided
with original or modified versions of the font.

This adds the missing information.

Signed-off-by: Stephen Kitt <steve@sk2.org>
2022-06-18 14:18:27 +02:00
Stephen Anthony 6a38fcef05 Fix automated Windows builds. 2022-06-14 17:49:47 -02:30
Stephen Anthony 3521f60225 Refactored 'FilesystemNode' -> 'FSNode', in preparation for large overhaul of these classes. 2022-06-14 16:28:20 -02:30
Stephen Anthony 93f6635ea8 Bumped version number for next release. It's probably some time away yet; certainly not this year.
One requirement is it will require C++17 fully. So that means g++-10 at minimum, Visual Studio 2022, and the latest version of Xcode.
2022-06-14 15:52:07 -02:30
Stephen Anthony 32e726b5f4 Updated to Visual Studio 2022. 2022-06-14 15:40:40 -02:30
997 changed files with 89890 additions and 48718 deletions

68
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,68 @@
---
name: Build
on:
pull_request:
push:
permissions: {}
jobs:
linux:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Install SDL2
run: |
sudo apt-get update
sudo apt-get install libsdl2-dev
- name: Build Stella
run: |
./configure && make -j2 all
macos:
name: macOS
runs-on: macos-latest
steps:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.2'
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Install SDL2
run: |
curl https://www.libsdl.org/release/SDL2-2.26.0.tar.gz | tar xzf -
mkdir SDL2-2.26.0/build
cd SDL2-2.26.0/build
../configure && make -j3 && sudo make install
- name: Build Stella
run: |
./configure && make -j3 all
windows:
name: Windows
runs-on: windows-latest
strategy:
matrix:
platform: [x64]
env:
Platform: ${{ matrix.platform }}
SDL2_version: 2.26.0
steps:
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Set up MSBUILD
uses: microsoft/setup-msbuild@34cfbaee7f672c76950673338facd8a73f637506
- name: Install SDL2
shell: cmd
run: |
curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip"
7z x "C:\SDL2-devel.zip" -o"C:\"
xcopy /S "C:\SDL2-%SDL2_version%\include" src\common
if %Platform%==x64 xcopy /S "C:\SDL2-%SDL2_version%\lib\x64" src\os\windows
- name: Build Stella
run: |
msbuild src\os\windows\Stella.sln

21
.gitignore vendored
View File

@ -10,7 +10,9 @@ src/**/*.tlog
out
out.pgo
out.pgen
out.test
stella
stella-test
stella-pgo
stella-pgo-generate
*.diff
@ -18,17 +20,17 @@ project.xcworkspace/
xcuserdata/
.DS_Store
build/
src/macosx/M6502.ins
src/os/macos/M6502.ins
*.dSYM
.vscode/c_cpp_properties.json
.vscode/settings.json
src/windows/sdl/*
src/windows/x64/*
src/windows/Win32/*
src/windows/Stella.vcxproj.user
src/windows/*.bak
src/libretro/x64/*
src/libretro/Stella.vcxproj.user
src/os/windows/sdl/*
src/os/windows/x64/*
src/os/windows/Win32/*
src/os/windows/Stella.vcxproj.user
src/os/windows/*.bak
src/os/libretro/x64/*
src/os/libretro/Stella.vcxproj.user
.vs/*
.tgitconfig
src/**/*.psess
@ -40,4 +42,5 @@ src/tools/fonts/*
a.out
*.json
*.sqlite3
*.bak
*.bak
debian/files

View File

@ -7,8 +7,8 @@
# Core definitions
.core-defs:
variables:
JNI_PATH: src/libretro
MAKEFILE_PATH: src/libretro
JNI_PATH: src/os/libretro
MAKEFILE_PATH: src/os/libretro
CORENAME: stella
# Inclusion templates, required for the build to work
@ -18,18 +18,10 @@ include:
- project: 'libretro-infrastructure/ci-templates'
file: '/windows-x64-mingw.yml'
# Windows 32-bit
- project: 'libretro-infrastructure/ci-templates'
file: '/windows-i686-mingw.yml'
# Linux 64-bit
- project: 'libretro-infrastructure/ci-templates'
file: '/linux-x64.yml'
# Linux 32-bit
- project: 'libretro-infrastructure/ci-templates'
file: '/linux-i686.yml'
# MacOS 64-bit
- project: 'libretro-infrastructure/ci-templates'
file: '/osx-x64.yml'
@ -59,7 +51,7 @@ include:
# tvOS (AppleTV)
- project: 'libretro-infrastructure/ci-templates'
file: '/tvos-arm64.yml'
#################################### MISC ##################################
# Stages for building
@ -79,73 +71,69 @@ libretro-build-windows-x64:
- .libretro-windows-x64-mingw-make-default
- .core-defs
# Windows 32-bit
libretro-build-windows-i686:
extends:
- .libretro-windows-i686-mingw-make-default
- .core-defs
# Linux 64-bit
libretro-build-linux-x64:
extends:
- .libretro-linux-x64-make-default
- .core-defs
# Linux 32-bit
libretro-build-linux-i686:
extends:
- .libretro-linux-i686-make-default
- .core-defs
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-amd64-ubuntu:latest
before_script:
- export NUMPROC=$(($(nproc)/5))
- sudo apt-get update -qy
- sudo apt-get install -qy software-properties-common
- sudo add-apt-repository -y ppa:savoury1/build-tools
- sudo add-apt-repository -y ppa:savoury1/gcc-defaults-12
- sudo apt-get update -qy
- sudo apt-get install -qy gcc-12 g++-12
# This container's existing installations of gcc and CMake are way too old
variables:
CC: /usr/bin/gcc-12
CXX: /usr/bin/g++-12
CXXFLAGS: -Wno-deprecated-declarations # Deprecation warnings aren't helpful on the libretro Gitlab
# MacOS 64-bit
libretro-build-osx-x64:
tags:
- mac-apple-silicon
extends:
- .libretro-osx-x64-make-default
- .core-defs
# MacOS ARM 64-bit
libretro-build-osx-arm64:
tags:
- mac-apple-silicon
extends:
- .libretro-osx-arm64-make-default
- .core-defs
################################### CELLULAR #################################
# Android ARMv7a
android-armeabi-v7a:
extends:
- .libretro-android-jni-armeabi-v7a
- .core-defs
# android-armeabi-v7a:
# extends:
# - .libretro-android-jni-armeabi-v7a
# - .core-defs
# Android ARMv8a
android-arm64-v8a:
extends:
- .libretro-android-jni-arm64-v8a
- .core-defs
# android-arm64-v8a:
# extends:
# - .libretro-android-jni-arm64-v8a
# - .core-defs
# Android 64-bit x86
android-x86_64:
extends:
- .libretro-android-jni-x86_64
- .core-defs
# Android 32-bit x86
android-x86:
extends:
- .libretro-android-jni-x86
- .core-defs
# android-x86_64:
# extends:
# - .libretro-android-jni-x86_64
# - .core-defs
# iOS
libretro-build-ios-arm64:
tags:
- mac-apple-silicon
extends:
- .libretro-ios-arm64-make-default
- .core-defs
# iOS (armv7) [iOS 9 and up]
libretro-build-ios9:
extends:
- .libretro-ios9-make-default
- .core-defs
# tvOS
libretro-build-tvos-arm64:
extends:
@ -154,7 +142,7 @@ libretro-build-tvos-arm64:
################################### CONSOLES #################################
# Nintendo Switch
libretro-build-libnx-aarch64:
extends:
- .libretro-libnx-static-retroarch-master
- .core-defs
# libretro-build-libnx-aarch64:
# extends:
# - .libretro-libnx-static-retroarch-master
# - .core-defs

View File

@ -1,63 +0,0 @@
# Build matrix / environment variables are explained on:
# http://about.travis-ci.org/docs/user/build-configuration/
# This file can be validated on: http://lint.travis-ci.org/
language: cpp
matrix:
include:
- os: linux
dist: xenial
compiler: gcc
env: GCC=9 CC=gcc-9 CXX=g++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-9
- g++-9
update: true
- os: osx
osx_image: xcode11.3
compiler: clang
addons:
homebrew:
update: true
install:
- |
old_cwd=$(pwd)
cd ~
if [[ "$HOST" == macosx-* ]]; then
curl -O https://www.libsdl.org/release/SDL2-2.0.10.tar.gz
tar xzf SDL2-2.0.10.tar.gz
cd SDL2-2.0.10/Xcode/SDL
sed -i -e 's/@rpath//g' SDL.xcodeproj/project.pbxproj
xcodebuild -configuration Release
mkdir -p ~/Library/Frameworks/
ln -s `pwd`/build/Release/SDL2.framework ~/Library/Frameworks/
else
curl -O https://www.libsdl.org/release/SDL2-2.0.10.tar.gz
tar xzf SDL2-2.0.10.tar.gz
cd SDL2-2.0.10
mkdir build
cd build
../configure
make
sudo make install
fi
cd $old_cwd
script:
- |
./configure
make all

15
.vscode/settings.json vendored
View File

@ -14,6 +14,7 @@
"C_Cpp.intelliSenseEngine": "Default",
"files.insertFinalNewline": true,
"files.associations": {
"*.h": "cpp",
"__functional_base": "cpp",
"array": "cpp",
"istream": "cpp",
@ -103,6 +104,18 @@
"version": "cpp",
"shared_mutex": "cpp",
"compare": "cpp",
"concepts": "cpp"
"concepts": "cpp",
"__verbose_abort": "cpp",
"any": "cpp",
"charconv": "cpp",
"csignal": "cpp",
"execution": "cpp",
"numbers": "cpp",
"span": "cpp",
"unordered_set": "cpp",
"variant": "cpp",
"hash_map": "cpp",
"format": "cpp",
"*.inc": "cpp"
}
}

View File

@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa
===========================================================================
Release 6.7.1 for Linux, macOS and Windows
Release 7.0 for Linux, macOS and Windows
===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@ -21,22 +21,21 @@ 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.7.1 release of Stella for Linux, macOS and Windows. The
This is the 7.0 release of Stella for Linux, macOS and Windows. The
distributions currently available are:
* Binaries for Windows 7/8/10/11 :
Stella-6.7.1-win32.exe (32-bit EXE installer)
Stella-6.7.1-x64.exe (64-bit EXE installer)
Stella-6.7.1-windows.zip (32/64 bit versions)
* Binary for Windows 7/8/10/11 :
Stella-7.0-x64.exe (64-bit EXE installer)
Stella-7.0-windows.zip (64 bit ZIP version)
* Binary distribution for macOS 10.7 and above :
Stella-6.7.1-macos.dmg (ARM M1 and 64-bit Intel)
* Binary distribution for macOS 10.13 and above :
Stella-7.0-macos.dmg (ARM M1 and 64-bit Intel)
* Binary distribution for 64-bit Ubuntu :
stella_6.7.1-1_amd64.deb
stella_7.0-1_amd64.deb
* Source code distribution for all platforms :
stella-6.7.1-src.tar.xz
stella-7.0-src.tar.xz
Distribution Site

View File

@ -12,6 +12,74 @@
Release History
===========================================================================
7.0 to 7.1 (xxx x, 202x)
* Added developer option for disabling PlusROM support (TODO: Doc)
* Enhanced PAL-60 detection, searches for signature (e.g. PAL60) in ROM
* Enhanced VSYNC emulation, considers VBLANK now too
6.7.1 to 7.0 (October 5, 2024)
* Enhanced ROM launcher to allow multiple images per ROM.
* Made heaps of additional images available for the ROM launcher.
* Added searching by filename for ROM launcher images.
* Added option to start random ROM.
* Added automatically enabled phosphor modes.
* Enhanced Game Properties dialog for multigame ROMs.
* Added 2nd UI theme and hotkey for toggling UI theme.
* Added bezel support (incl. Sinden Lightgun).
* Added optional type format detection based on colors used.
* Added Joy2B+ controller support.
* Added auto detection for QuadTari attached controllers.
* Enhanced Kid Vid support to play tape audio.
* Added port selection, used for controller default mapping.
* Added missing PlusROM support for E7 bankswitching.
* Enhanced movie cart (MVC) support.
* Accelerated emulation up to ~15% (ARM).
* Added limited GameLine Master Module bankswitching support.
* Added 03E0 bankswitching for Brazilian Parker Bros ROMs.
* Added WF8 bankswitching used by some certain Coleco white carts.
* Added JANE bankswitching used by Coleco's Tarzan prototype.
* Added ELF mapper for Mattress Monkeys.
* Added BUS bankswitching support for some older demos.
* Fixed broken 7800 pause key support.
* Added developer option for random hotspot peek values.
* Added user defined CPU cycle timers to debugger.
* Removed 'launcherroms' option, since it was causing some issues.
* Codebase now uses C++20 features, which means a minimum of gcc-11
or clang-10 for Linux/Mac, and Visual Studio 2022 for Windows.
-Have fun!
6.7 to 6.7.1 (January 15, 2024)
* Fixed broken mouse and Stelladaptor input for Driving Controller.
@ -20,8 +88,6 @@
when available, and fixes delay on exiting app experienced on some
systems.
-Have fun!
6.6 to 6.7 (June 13, 2022)

View File

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

View File

@ -8,7 +8,7 @@
## SS SS tt ee ll ll aa aa
## SSSS ttt eeeee llll llll aaaaa
##
## Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
## Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
## and the Stella Team
##
## See the file "License.txt" for information on usage and redistribution of
@ -26,6 +26,7 @@ LDFLAGS := -pthread
INCLUDES :=
LIBS :=
OBJS :=
OBJS_TEST :=
PROF :=
MODULES :=
@ -47,29 +48,53 @@ else
CFLAGS:= -O2
endif
ifndef CXXFLAGS_TEST
CXXFLAGS_TEST := $(CXXFLAGS)
endif
ifndef CFLAGS_TEST
CFLAGS_TEST := $(CFLAGS)
endif
ifndef LDFLAGS_TEST
LDFLAGS_TEST := $(LDFLAGS)
endif
CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter
CFLAGS+= -Wall -Wextra -Wno-unused-parameter
CXXFLAGS_TEST+= -Wall -Wextra -Wno-unused-parameter
CFLAGS_TEST+= -Wall -Wextra -Wno-unused-parameter
ifdef HAVE_GCC
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
CFLAGS+= -Wno-multichar -Wunused
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
CFLAGS+= -Wunused
CXXFLAGS_TEST+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
CFLAGS_TEST+= -Wno-multichar -Wunused
endif
ifdef HAVE_CLANG
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
CFLAGS+= -Wno-multichar -Wunused
CXXFLAGS+= -Wunused -Woverloaded-virtual -std=c++20
CFLAGS+= -Wunused
CXXFLAGS_TEST+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
CFLAGS_TEST+= -Wno-multichar -Wunused
endif
ifdef CLANG_WARNINGS
EXTRA_WARN=-Weverything -Wno-c++98-compat-pedantic -Wno-unknown-warning-option \
EXTRA_WARN=-Wno-c++98-compat-pedantic -Wno-undefined-func-template \
-Wno-switch-enum -Wno-conversion -Wno-covered-switch-default \
-Wno-inconsistent-missing-destructor-override -Wno-float-equal \
-Wno-documentation -Wno-float-equal \
-Wno-exit-time-destructors -Wno-global-constructors -Wno-weak-vtables \
-Wno-four-char-constants -Wno-padded -Wno-reserved-identifier \
-Wno-duplicate-enum
-Wno-duplicate-enum -Wno-unsafe-buffer-usage
CXXFLAGS+= $(EXTRA_WARN)
CFLAGS+= $(EXTRA_WARN)
CXXFLAGS_TEST+= $(EXTRA_WARN)
CFLAGS_TEST+= $(EXTRA_WARN)
endif
ifdef PROFILE
@ -108,12 +133,14 @@ ifdef STELLA_BUILD_ROOT
else
OBJECT_ROOT := out
endif
OBJECT_ROOT_TEST := out.test
OBJECT_ROOT_PROFILE_GENERERATE := out.pgen
OBJECT_ROOT_PROFILE_USE := out.pgo
EXECUTABLE := stella$(EXEEXT)
EXECUTABLE_PROFILE_GENERATE := stella-pgo-generate$(EXEEXT)
EXECUTABLE_PROFILE_USE := stella-pgo$(EXEEXT)
EXECUTABLE_TEST := stella-test$(EXEEXT)
PROFILE_DIR = $(CURDIR)/test/roms/profile
PROFILE_OUT = $(PROFILE_DIR)/out
@ -154,6 +181,9 @@ all: $(EXECUTABLE)
pgo: $(EXECUTABLE_PROFILE_USE)
test: $(EXECUTABLE_TEST)
./$(EXECUTABLE_TEST)
######################################################################
# Various minor settings
######################################################################
@ -176,6 +206,7 @@ MODULES += \
src/emucore \
src/emucore/tia \
src/emucore/tia/frame-manager \
src/emucore/elf \
src/common/repository/sqlite
######################################################################
@ -194,6 +225,7 @@ DEPDIRS = $(addsuffix /$(DEPDIR),$(MODULE_DIRS))
DEPFILES =
OBJ=$(addprefix $(OBJECT_ROOT)/,$(OBJS))
OBJ_TEST=$(addprefix $(OBJECT_ROOT_TEST)/,$(OBJS_TEST))
OBJ_PROFILE_GENERATE=$(addprefix $(OBJECT_ROOT_PROFILE_GENERERATE)/,$(OBJS))
OBJ_PROFILE_USE=$(addprefix $(OBJECT_ROOT_PROFILE_USE)/,$(OBJS))
@ -201,6 +233,9 @@ OBJ_PROFILE_USE=$(addprefix $(OBJECT_ROOT_PROFILE_USE)/,$(OBJS))
$(EXECUTABLE): $(OBJ)
$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) $(PROF) -o $@
$(EXECUTABLE_TEST): $(OBJ_TEST)
$(LD) $(LDFLAGS_TEST) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -lgtest -lgtest_main -o $@
$(EXECUTABLE_PROFILE_GENERATE): $(OBJ_PROFILE_GENERATE)
$(LD) $(LDFLAGS_PROFILE_GENERATE) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) $(PROF) -o $@
@ -215,7 +250,7 @@ clean:
-$(RM) -fr \
$(OBJECT_ROOT) $(OBJECT_ROOT_PROFILE_GENERERATE) $(OBJECT_ROOT_PROFILE_USE) \
$(EXECUTABLE) $(EXECUTABLE_PROFILE_GENERATE) $(EXECUTABLE_PROFILE_USE) \
$(PROFILE_OUT) $(PROFILE_STAMP)
$(OBJECT_ROOT_TEST) $(PROFILE_OUT) $(PROFILE_STAMP)
.PHONY: all clean dist distclean
@ -243,6 +278,16 @@ $(OBJECT_ROOT)/%.o: %.cxx
$(merge_dep)
$(OBJECT_ROOT)/%.o: %.c
$(create_dir)
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
$(merge_dep)
$(OBJECT_ROOT_TEST)/%.o: %.cxx
$(create_dir)
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
$(merge_dep)
$(OBJECT_ROOT_TEST)/%.o: %.c
$(create_dir)
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS) $(CPPFLAGS) -c $(<) -o $@
$(merge_dep)
@ -280,6 +325,14 @@ $(OBJECT_ROOT)/%.o: %.c
$(create_dir)
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS) $(CPPFLAGS) -c $(<) -o $@
$(OBJECT_ROOT_TEST)/%.o: %.cxx
$(create_dir)
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
$(OBJECT_ROOT_TEST)/%.o: %.c
$(create_dir)
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
$(OBJECT_ROOT_PROFILE_GENERERATE)/%.o: %.cxx
$(create_dir)
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_PROFILE_GENERATE) $(CPPFLAGS) -c $(<) -o $@
@ -317,11 +370,11 @@ install: all
$(INSTALL) -d "$(DESTDIR)$(BINDIR)"
$(INSTALL) -c -m 755 "$(srcdir)/stella$(EXEEXT)" "$(DESTDIR)$(BINDIR)/stella$(EXEEXT)"
$(INSTALL) -d "$(DESTDIR)$(DOCDIR)"
$(INSTALL) -c -m 644 "$(srcdir)/Announce.txt" "$(srcdir)/Changes.txt" "$(srcdir)/Copyright.txt" "$(srcdir)/License.txt" "$(srcdir)/README-SDL.txt" "$(srcdir)/Readme.txt" "$(srcdir)/Todo.txt" "$(srcdir)/docs/index.html" "$(srcdir)/docs/debugger.html" "$(DESTDIR)$(DOCDIR)/"
$(INSTALL) -c -m 644 "$(srcdir)/Announce.txt" "$(srcdir)/Changes.txt" "$(srcdir)/Copyright.txt" "$(srcdir)/License.txt" "$(srcdir)/README-SDL.txt" "$(srcdir)/README.md" "$(srcdir)/Todo.txt" "$(srcdir)/docs/index.html" "$(srcdir)/docs/debugger.html" "$(DESTDIR)$(DOCDIR)/"
$(INSTALL) -d "$(DESTDIR)$(DOCDIR)/graphics"
$(INSTALL) -c -m 644 $(wildcard $(srcdir)/docs/graphics/*.png) "$(DESTDIR)$(DOCDIR)/graphics"
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/applications"
$(INSTALL) -c -m 644 "$(srcdir)/src/unix/stella.desktop" "$(DESTDIR)$(DATADIR)/applications"
$(INSTALL) -c -m 644 "$(srcdir)/src/os/unix/stella.desktop" "$(DESTDIR)$(DATADIR)/applications"
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/16x16/apps"
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/22x22/apps"
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/24x24/apps"
@ -357,7 +410,7 @@ src/emucore/M6502.ins: src/emucore/M6502.m4
m4 src/emucore/M6502.m4 > src/emucore/M6502.ins
# Special rule for windows icon stuff (there's probably a better way to do this ...)
src/windows/stella_icon.o: src/windows/stella.ico src/windows/stella.rc
windres --include-dir src/windows src/windows/stella.rc src/windows/stella_icon.o
src/os/windows/stella_icon.o: src/os/windows/stella.ico src/os/windows/stella.rc
windres --include-dir src/os/windows src/os/windows/stella.rc src/os/windows/stella_icon.o
.PHONY: deb bundle test install uninstall

View File

@ -15,6 +15,10 @@ Please check the list of known issues first (see below) before reporting new one
If you encounter any issues, please open a new issue on the project
[issue tracker](https://github.com/stella-emu/stella/issues).
Note: Please do **not** report issues regarding platforms other than PC and RetroN 77
(e.g. Libretro) here. The Stella Team is not responsible for these forks and cannot
help with them.
# Known issues
Please check out the [issue tracker](https://github.com/stella-emu/stella/issues) for

View File

@ -1,10 +0,0 @@
Stella is a multi-platform Atari 2600 VCS emulator which allows you to
play all of your favourite Atari 2600 games on your PC. You'll find the
Stella Users Manual in the docs subdirectory. If you'd like to verify
that you have the latest release of Stella, visit the Stella Website at:
https://stella-emu.github.io
Enjoy,
The Stella Team

View File

@ -1,32 +0,0 @@
image: Visual Studio 2019
shallow_clone: true
environment:
matrix:
- Platform: x64
- Platform: Win32
Configuration: Release
SDL2_version: 2.0.12
install:
- cmd: |
curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip"
7z x "C:\SDL2-devel.zip" -o"C:\"
xcopy /S "C:\SDL2-%SDL2_version%\include" src\common
if %Platform%==x64 xcopy /S "C:\SDL2-%SDL2_version%\lib\x64" src\windows
if %Platform%==Win32 xcopy /S "C:\SDL2-%SDL2_version%\lib\x86" src\windows
build_script:
- cmd: |
msbuild src\windows\Stella.sln
artifacts:
- path: '**\stella.exe'

View File

@ -4,7 +4,9 @@
# contains the module name, a trick we use so we can keep multiple different
# module object lists, one for each module.
MODULE_OBJS-$(MODULE) := $(MODULE_OBJS)
MODULE_TEST_OBJS-$(MODULE) := $(MODULE_TEST_OBJS)
# If not building as a plugin, add the object files to the main OBJS list
#OBJS += $(MODULE_LIB-$(MODULE))
OBJS += $(MODULE_OBJS)
OBJS_TEST += $(MODULE_TEST_OBJS)

121
config.guess vendored
View File

@ -1,14 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2021 Free Software Foundation, Inc.
# Copyright 1992-2024 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2021-06-03'
timestamp='2024-07-27'
# This file 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 3 of the License, or
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on.
Output the configuration name of the system '$me' is run on.
Options:
-h, --help print this help, then exit
@ -60,13 +60,13 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2021 Free Software Foundation, Inc.
Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@ -102,8 +102,8 @@ GUESS=
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.
# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
# use 'HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
@ -123,7 +123,7 @@ set_cc_for_build() {
dummy=$tmp/dummy
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
,,) echo "int x;" > "$dummy.c"
for driver in cc gcc c89 c99 ; do
for driver in cc gcc c17 c99 c89 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
CC_FOR_BUILD=$driver
break
@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
set_cc_for_build
cat <<-EOF > "$dummy.c"
#if defined(__ANDROID__)
LIBC=android
#else
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
LIBC=dietlibc
#elif defined(__GLIBC__)
LIBC=gnu
#elif defined(__LLVM_LIBC__)
LIBC=llvm
#else
#include <stdarg.h>
/* First heuristic to detect musl libc. */
@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
LIBC=musl
#endif
#endif
#endif
EOF
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
eval "$cc_set_libc"
@ -437,7 +443,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
# This test works for both compilers.
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
(CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH=x86_64
@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
# Japanese Language versions have a version number like '4.1.3-JL'.
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
GUESS=sparc-sun-sunos$SUN_REL
;;
@ -628,7 +634,8 @@ EOF
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
main()
int
main ()
{
if (!__power_pc())
exit(1);
@ -712,7 +719,8 @@ EOF
#include <stdlib.h>
#include <unistd.h>
int main ()
int
main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
@ -904,7 +912,7 @@ EOF
fi
;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
@ -929,6 +937,9 @@ EOF
i*:PW*:*)
GUESS=$UNAME_MACHINE-pc-pw32
;;
*:SerenityOS:*:*)
GUESS=$UNAME_MACHINE-pc-serenity
;;
*:Interix*:*)
case $UNAME_MACHINE in
x86)
@ -963,11 +974,37 @@ EOF
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
;;
x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
;;
*:[Mm]anagarm:*:*)
GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
;;
*:Minix:*:*)
GUESS=$UNAME_MACHINE-unknown-minix
;;
aarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
set_cc_for_build
CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
ABI=64
sed 's/^ //' << EOF > "$dummy.c"
#ifdef __ARM_EABI__
#ifdef __ARM_PCS_VFP
ABI=eabihf
#else
ABI=eabi
#endif
#endif
EOF
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
eval "$cc_set_abi"
case $ABI in
eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
esac
fi
GUESS=$CPU-unknown-linux-$LIBCABI
;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
@ -1033,7 +1070,16 @@ EOF
k1om:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
kvx:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
kvx:cos:*:*)
GUESS=$UNAME_MACHINE-unknown-cos
;;
kvx:mbr:*:*)
GUESS=$UNAME_MACHINE-unknown-mbr
;;
loongarch32:Linux:*:* | loongarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
m32r*:Linux:*:*)
@ -1148,16 +1194,27 @@ EOF
;;
x86_64:Linux:*:*)
set_cc_for_build
CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_X32 >/dev/null
then
LIBCABI=${LIBC}x32
fi
ABI=64
sed 's/^ //' << EOF > "$dummy.c"
#ifdef __i386__
ABI=x86
#else
#ifdef __ILP32__
ABI=x32
#endif
#endif
EOF
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
eval "$cc_set_abi"
case $ABI in
x86) CPU=i686 ;;
x32) LIBCABI=${LIBC}x32 ;;
esac
fi
GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
GUESS=$CPU-pc-linux-$LIBCABI
;;
xtensa*:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
@ -1177,7 +1234,7 @@ EOF
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# If we were able to find 'uname', then EMX Unix compatibility
# is probably installed.
GUESS=$UNAME_MACHINE-pc-os2-emx
;;
@ -1318,7 +1375,7 @@ EOF
GUESS=ns32k-sni-sysv
fi
;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
GUESS=i586-unisys-sysv4
;;
@ -1364,8 +1421,11 @@ EOF
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
GUESS=i586-pc-haiku
;;
x86_64:Haiku:*:*)
GUESS=x86_64-unknown-haiku
ppc:Haiku:*:*) # Haiku running on Apple PowerPC
GUESS=powerpc-apple-haiku
;;
*:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
GUESS=$UNAME_MACHINE-unknown-haiku
;;
SX-4:SUPER-UX:*:*)
GUESS=sx4-nec-superux$UNAME_RELEASE
@ -1522,6 +1582,9 @@ EOF
i*86:rdos:*:*)
GUESS=$UNAME_MACHINE-pc-rdos
;;
i*86:Fiwix:*:*)
GUESS=$UNAME_MACHINE-pc-fiwix
;;
*:AROS:*:*)
GUESS=$UNAME_MACHINE-unknown-aros
;;
@ -1534,6 +1597,9 @@ EOF
*:Unleashed:*:*)
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
;;
*:Ironclad:*:*)
GUESS=$UNAME_MACHINE-unknown-ironclad
;;
esac
# Do we have a guess based on uname results?
@ -1557,6 +1623,7 @@ cat > "$dummy.c" <<EOF
#endif
#endif
#endif
int
main ()
{
#if defined (sony)

952
config.sub vendored

File diff suppressed because it is too large Load Diff

98
configure vendored
View File

@ -13,6 +13,16 @@
# use environment vars if set
CXXFLAGS="$CXXFLAGS $CPPFLAGS"
if test -n "$CXXFLAGS_TEST"; then
CXXFLAGS_TEST="$CXXFLAGS_TEST $CPPFLAGS"
else
CXXFLAGS_TEST="$CXXFLAGS"
fi
if test -z "$LDFLAGS_TEST"; then
LDFLAGS_TEST="$LDFLAGS"
fi
# default option behaviour yes/no
_build_gui=yes
_build_windowed=yes
@ -28,12 +38,14 @@ _build_static=no
_build_profile=no
_build_debug=no
_build_release=no
_build_mold=no
# more defaults
_ranlib=ranlib
_install=install
_ar="ar cru"
_strip=strip
_pkg_config=pkg-config
_mkdir="mkdir -p"
_echo=printf
_cat=cat
@ -218,11 +230,13 @@ Optional Features:
--disable-debug
--enable-release build with all optimizations, for final release [disabled]
--disable-release
--use-mold-linker use mold linker (experimental) [disabled]
Optional Libraries:
--with-sdl-prefix=DIR Prefix where the sdl2-config script is installed (optional)
--with-libpng-prefix=DIR Prefix where libpng is installed (optional)
--with-zlib-prefix=DIR Prefix where zlib is installed (optional)
--with-gtest-prefix=DIR Prefix where googletest is installed (optional)
Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
@ -231,6 +245,8 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags
CPPFLAGS C++ preprocessor flags, e.g. -I<include dir> if you have
headers in a nonstandard directory <include dir>
LDFLAGS_TEST linker flags for unit tests
CXXFLAGS_TEST C++ compiler flags for unit tests
EOF
exit 0
@ -264,6 +280,7 @@ for ac_option in $@; do
--disable-debug) _build_debug=no ;;
--enable-release) _build_release=yes ;;
--disable-release) _build_release=no ;;
--use-mold-linker) _build_mold=yes ;;
--with-sdl-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
_sdlpath="$arg:$arg/bin"
@ -277,6 +294,11 @@ for ac_option in $@; do
_prefix=`echo $ac_option | cut -d '=' -f 2`
ZLIB_CFLAGS="-I$_prefix/include"
ZLIB_LIBS="-L$_prefix/lib"
;;
--with-gtest-prefix=*)
_prefix=`echo $ac_option | cut -d '=' -f 2`
CXXFLAGS_TEST="$CXXFLAGS_TEST -I$_prefix/include"
LDFLAGS_TEST="$LDFLAGS_TEST -L$_prefix/lib"
;;
--host=*)
_host=`echo $ac_option | cut -d '=' -f 2`
@ -322,12 +344,17 @@ mingw32-cross)
_host_cpu=i386
_host_prefix=i386-mingw32msvc
;;
*)
"")
guessed_host=`$_srcdir/config.guess`
_host_cpu=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
_host_os=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
_host_vendor=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
;;
*)
_host_cpu=`echo "$_host" | sed 's/^\([^-]*\)-.*/\1/'`
_host_os=`echo "$_host" | sed 's/-\([^-]*\)-[^-]*$/\1/'`
_host_prefix="$_host"
;;
esac
#
@ -343,9 +370,6 @@ arm-riscos-aof)
psp)
EXEEXT=".elf"
;;
gp2x)
EXEEXT=""
;;
*)
EXEEXT=""
;;
@ -378,7 +402,7 @@ else
fi
for compiler in $compilers; do
if test_compiler "$compiler -std=c++17"; then
if test_compiler "$compiler -std=c++20"; then
CXX=$compiler
echo $CXX
break
@ -608,6 +632,9 @@ fi
# Cross-compilers use their own commands for the following functions
if test -n "$_host_prefix"; then
_strip="$_host_prefix-$_strip"
if command -v "$_host_prefix-$_pkg_config" >/dev/null 2>&1; then
_pkg_config="$_host_prefix-$_pkg_config"
fi
fi
#
@ -621,7 +648,7 @@ if test "$_build_zip" = yes ; then
#include <zlib.h>
int main(void) { return strcmp(ZLIB_VERSION, zlibVersion()); }
EOF
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `pkg-config --libs zlib` && _zlib=yes
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `$_pkg_config --libs zlib` && _zlib=yes
if test "$_zlib" = yes ; then
echo "$_zlib"
@ -647,7 +674,7 @@ if test "$_build_png" = yes ; then
#include <png.h>
int main(void) { return printf("%s\n", PNG_HEADER_VERSION_STRING); }
EOF
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `pkg-config --libs libpng` && _libpng=yes
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `$_pkg_config --libs libpng` && _libpng=yes
if test "$_libpng" = yes ; then
echo "$_libpng"
@ -671,7 +698,7 @@ if test "$_build_sqlite3" = yes ; then
#include <sqlite3.h>
int main(void) { return printf("%s\n", SQLITE_VERSION); }
EOF
cc_check $LDFLAGS $CXXFLAGS `pkg-config --libs sqlite3` && _libsqlite3=yes
cc_check $LDFLAGS $CXXFLAGS `$_pkg_config --libs sqlite3` && _libsqlite3=yes
if test "$_libsqlite3" = yes ; then
echo "$_libsqlite3"
@ -794,24 +821,29 @@ echo
find_sdlconfig
SRC="src"
SRC_OS="$SRC/os"
SRC_LIB="$SRC/lib"
CORE="$SRC/emucore"
COMMON="$SRC/common"
TIA="$SRC/emucore/tia"
ELF="$SRC/emucore/elf"
TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager"
TV="$SRC/common/tv_filters"
GUI="$SRC/gui"
DBG="$SRC/debugger"
DBGGUI="$SRC/debugger/gui"
YACC="$SRC/yacc"
YACC="$SRC/debugger/yacc"
CHEAT="$SRC/cheat"
LIBPNG="$SRC/libpng"
ZLIB="$SRC/zlib"
LIBPNG="$SRC_LIB/libpng"
LIBJPG="$SRC_LIB/nanojpeg"
LIBJPGEXIF="$SRC_LIB/tinyexif"
ZLIB="$SRC_LIB/zlib"
SQLITE_REPO="$SRC/common/repository/sqlite"
SQLITE_LIB="$SRC/sqlite"
JSON="$SRC/json"
HTTP_LIB="$SRC/httplib"
SQLITE_LIB="$SRC_LIB/sqlite"
JSON="$SRC_LIB/json"
HTTP_LIB="$SRC_LIB/httplib"
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$JSON -I$SQLITE_REPO"
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$ELF -I$JSON -I$SQLITE_REPO"
INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
if test "$_build_static" = yes ; then
@ -827,26 +859,30 @@ LD=$CXX
case $_host_os in
unix)
DEFINES="$DEFINES -DBSPF_UNIX"
MODULES="$MODULES $SRC/unix"
INCLUDES="$INCLUDES -I$SRC/unix"
MODULES="$MODULES $SRC_OS/unix"
INCLUDES="$INCLUDES -I$SRC_OS/unix"
;;
darwin)
DEFINES="$DEFINES -DBSPF_UNIX -DMACOS_KEYS"
MODULES="$MODULES $SRC/unix"
INCLUDES="$INCLUDES -I$SRC/unix"
MODULES="$MODULES $SRC_OS/unix"
INCLUDES="$INCLUDES -I$SRC_OS/unix"
if test "$have_clang" == yes; then
CXXFLAGS="$CXXFLAGS -Wno-poison-system-directories"
if test -n "$CXXFLAGS_TEST"; then
CXXFLAGS_TEST="$CXXFLAGS_TEST -Wno-poison-system-directories"
fi
fi
_libsqlite3=no
;;
retron77)
DEFINES="$DEFINES -DBSPF_UNIX -DRETRON77"
MODULES="$MODULES $SRC/unix $SRC/unix/r77"
INCLUDES="$INCLUDES -I$SRC/unix -I$SRC/unix/r77"
MODULES="$MODULES $SRC_OS/unix $SRC_OS/unix/r77"
INCLUDES="$INCLUDES -I$SRC_OS/unix -I$SRC_OS/unix/r77"
;;
win32)
DEFINES="$DEFINES -DBSPF_WINDOWS"
MODULES="$MODULES $SRC/windows"
INCLUDES="$INCLUDES -I$SRC/windows"
MODULES="$MODULES $SRC_OS/windows"
INCLUDES="$INCLUDES -I$SRC_OS/windows"
LIBS="$LIBS -lmingw32 -lwinmm"
;;
*)
@ -891,9 +927,11 @@ if test "$_build_httplib" = yes ; then
fi
if test "$_build_png" = yes ; then
DEFINES="$DEFINES -DPNG_SUPPORT"
DEFINES="$DEFINES -DIMAGE_SUPPORT"
INCLUDES="$INCLUDES -I$LIBJPG -I$LIBJPGEXIF"
MODULES="$MODULES $LIBJPGEXIF"
if test "$_libpng" = yes ; then
LIBS="$LIBS `pkg-config --libs libpng`"
LIBS="$LIBS `$_pkg_config --libs libpng`"
else
MODULES="$MODULES $LIBPNG"
INCLUDES="$INCLUDES -I$LIBPNG"
@ -901,7 +939,7 @@ if test "$_build_png" = yes ; then
fi
if test "$_libsqlite3" = yes ; then
LIBS="$LIBS `pkg-config --libs sqlite3`"
LIBS="$LIBS `$_pkg_config --libs sqlite3`"
else
MODULES="$MODULES $SQLITE_LIB"
INCLUDES="$INCLUDES -I$SQLITE_LIB"
@ -910,7 +948,7 @@ fi
if test "$_build_zip" = yes ; then
DEFINES="$DEFINES -DZIP_SUPPORT"
if test "$_zlib" = yes ; then
LIBS="$LIBS `pkg-config --libs zlib`"
LIBS="$LIBS `$_pkg_config --libs zlib`"
else
MODULES="$MODULES $ZLIB"
INCLUDES="$INCLUDES -I$ZLIB"
@ -929,6 +967,10 @@ if test "$_build_release" = no ; then
_build_release=
fi
if test "$_build_mold" = yes ; then
LDFLAGS="-fuse-ld=mold"
fi
# Workaround until we deal with autodetection of C compiler properly
# Or we remove C files from Stella entirely, by making them C++
if test -z "$CC"; then
@ -942,6 +984,7 @@ cat > config.mak << EOF
CC := $CC
CXX := $CXX
CXXFLAGS := $CXXFLAGS
CXXFLAGS_TEST := $CXXFLAGS_TEST
LD := $LD
LIBS += $LIBS
RANLIB := $_ranlib
@ -979,6 +1022,7 @@ INCLUDES += $INCLUDES
OBJS += $OBJS
DEFINES += $DEFINES
LDFLAGS += $LDFLAGS
LDFLAGS_TEST += $LDFLAGS_TEST
$_config_mk_data
EOF

6
debian/changelog vendored
View File

@ -1,8 +1,8 @@
stella (6.7.1) stable; urgency=high
stella (7.0) stable; urgency=high
* Version 6.7.1 release
* Version 7.0 release
-- Stephen Anthony <sa666666@gmail.com> Mon, 15 Jan 2024 17:09:59 -0230
-- Stephen Anthony <sa666666@gmail.com> Sat, 5 Oct 2024 17:09:59 -0230
stella (6.7) stable; urgency=high

1
debian/control vendored
View File

@ -3,6 +3,7 @@ Maintainer: Stephen Anthony <sa666666@gmail.com>
Section: otherosfs
Priority: optional
Build-Depends: debhelper (>= 10~),
libgtest-dev,
libpng-dev,
libsdl2-dev,
zlib1g-dev

14
debian/copyright vendored
View File

@ -1,18 +1,18 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0
Upstream-Name: stella
Source: https://stella-emu.github.io
Copyright: 1995-2022 Bradford W. Mott, Stephen Anthony and the Stella Team
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella Team
License: GPL-2+
Files: *
Copyright: 1995-2022 Bradford W. Mott, Stephen Anthony and the Stella
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella
Team
License: GPL-2+
Files: debian/*
Copyright: 1998-2004 Tom Lear <tom@trap.mtview.ca.us>
2006 Mario Iseli <admin@marioiseli.com>
2010-2022 Stephen Kitt <skitt@debian.org>
2010-2025 Stephen Kitt <skitt@debian.org>
License: GPL-2+
Files:
@ -73,7 +73,7 @@ License: RSA
These notices must be retained in any copies of any part of this
documentation and/or software.
Files: src/libpng/*
Files: src/lib/libpng/*
Copyright: 1995-1996 Guy Eric Schalnat, Group 42, Inc.
1996-1997 Andreas Dilger
1998-2013 Glenn Randers-Pehrson
@ -112,7 +112,7 @@ License: libpng
risk of satisfactory quality, performance, accuracy, and effort is
with the user.
Files: src/libretro/libretro.h
Files: src/os/libretro/libretro.h
Copyright: 2010-2017 The RetroArch team
License: MIT
Permission is hereby granted, free of charge, to any person obtaining
@ -135,7 +135,7 @@ License: MIT
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Files: src/macos/*
Files: src/os/macos/*
Copyright: 2005-2006 Mark Grebe
License: GPL-2+
@ -164,7 +164,7 @@ License: GPL-2
License version 2 can be found in
`/usr/share/common-licenses/GPL-2'.
Files: src/zlib/*
Files: src/lib/zlib/*
Copyright: 1995-2012, 2016 Jean-loup Gailly and Mark Adler
License: zlib
This software is provided 'as-is', without any express or implied

2
debian/docs vendored
View File

@ -2,7 +2,7 @@ Announce.txt
Changes.txt
Copyright.txt
README-SDL.txt
Readme.txt
README.md
docs/*.html
docs/graphics/*.png
Todo.txt

View File

@ -15,7 +15,7 @@
<body>
<center><b><font size="7">Stella</font></b></center>
<center><h4><b>Release 6.7.1</b></h4></center>
<center><h4><b>Release 7.0</b></h4></center>
<center><h1><b>Integrated Debugger</b></h1></center>
<center><h4><b>(a work in progress)</b></h4></center>
<br>
@ -45,6 +45,7 @@
<li><a href="#PseudoRegisters">Pseudo-Registers</a></li>
<li><a href="#Watches">Watches</a></li>
<li><a href="#Traps">Traps</a></li>
<li><a href="#Timers">Timers</a></li>
</ul>
</li>
<li><a href="#SaveWork">Save your work!</a></li>
@ -310,7 +311,7 @@ more convenient.
</li>
<li>
"&lt;rom_filename&gt;.sym" (located in the same directory as the ROM)</br>
If you provied the -l and -s parameters DASM will create these two files during
If you provide the -l and -s parameters DASM will create these two files during
assembly. Stella uses the file content to display the correct labels.
</li>
</ul>
@ -858,6 +859,22 @@ can remove a trap with "delTrap number", where the number comes from
"listTraps" or by entering the identical trap again. You can get rid of
all traps at once with the "clearTraps" command.</p></p>
<h4><a name="Timers">Timers</a></h4>
<p>Timers are used to measure cycles used between two timer points. They
measure the minimum, maximum and average cycles executed between their two
timer points. Start and end points can be set via prompt command or ROM
Disassembly settings dialog.</p>
<p>If the timer point is defined without an address or bank, the current PC
address or bank are used. If a '+' is added, both timer points use address
mirrors too, a '*' triggers both timer points in any bank.</p>
<p>All timers can be shown in detail with "listTimers", a single timer
with "printTimer number". "resetTimers" allows resetting all timer statistics,
"delTimer number" removes a single timer. All timers can be deleted with the
"clearTimers" command.</p>
</br>
<h3><a name="SaveWork">Save your work!</a></h3>
<p>Stella offers several commands to save your work inside the debugger for
@ -945,6 +962,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
clearConfig - Clear DiStella config directives [bank xx]
clearHistory - Clear the prompt history
clearSaveStateIfs - Clear all saveState points
clearTimers - Clear all timers
clearTraps - Clear all traps
clearWatches - Clear all watches
cls - Clear prompt area of text
@ -959,6 +977,7 @@ clearSaveStateIfs - Clear all saveState points
delFunction - Delete function with label xx
delSaveStateIf - Delete conditional saveState point &lt;xx&gt;
delTrap - Delete trap &lt;xx&gt;
delTimer - Delete timer &lt;xx&gt;
delWatch - Delete watch &lt;xx&gt;
disAsm - Disassemble address xx [yy lines] (default=PC)
dump - Dump data at address &lt;xx&gt; [to yy] [1: memory; 2: CPU state; 4: input regs] [?]
@ -988,14 +1007,17 @@ clearSaveStateIfs - Clear all saveState points
loadAllStates - Load all emulator states
loadState - Load emulator state xx (0-9)
logBreaks - Logs breaks and traps and continues emulation
logTrace - Logs emulation (note: emulation may slow down and the log becomes huge soon)
n - Negative Flag: set (0 or 1), or toggle (no arg)
palette - Show current TIA palette
pc - Set Program Counter to address xx
pCol - Mark 'PCOL' range in disassembly
pGfx - Mark 'PGFX' range in disassembly
print - Evaluate/print expression xx in hex/dec/binary
printTimer - Print details of timer xx
ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
reset - Reset system to power-on state
resetTimers - Reset all timers' statistics
rewind - Rewind state by one or [xx] steps/traces/scanlines/frames...
riot - Show RIOT timer/input status
rom - Set ROM address xx to yy1 [yy2 ...]
@ -1017,7 +1039,9 @@ clearSaveStateIfs - Clear all saveState points
scanLine - Advance emulation by &lt;xx&gt; scanlines (default=1)
step - Single step CPU [with count xx]
stepWhile - Single step CPU while &lt;condition&gt; is true
swchb - Set SWCHB to value xx
tia - Show TIA state
timer - Set a timer point
trace - Single step CPU over subroutines [with count xx]
trap - Trap read/write access to address(es) xx [yy]
trapIf - On &lt;condition&gt; trap R/W access to address(es) xx [yy]
@ -1084,7 +1108,7 @@ VDELBL selects the register that is used to control the ball. This is
visualized in the debugger in the same way as the two copies of GRP0 and
GRP1</p>
<p>For many registers, writes don't take effect immediatelly as the
<p>For many registers, writes don't take effect immediately as the
TIA takes some color clocks to change state. In Stella's TIA core, this
is implemented by queueing the writes, and the contents of this queue
are visualized in the debugger in the "Queued Writes" area of the TIA tab.</p>
@ -1562,13 +1586,16 @@ matches the address of the disassembly line where the mouse was clicked.</li>
<li><b>Disassemble @ current line</b>: Disassemble from the disassembly line where the mouse was clicked.
This allows to fill gaps in the disassembly and is most useful for bankswitched ROMs.</li>
<li><b>Set timer @ current line</b>: Set a timer point using the current
disassembly line's address and bank</li>
<li><b>Show tentative code</b>: Allow DiStella to do a static analysis/disassembly.</li>
<li><b>Show PC addresses</b>: Show Program Counter addresses as labels (where there
isn't already a defined label).</li>
<li><b>Show GFX as binary</b>: Switch between displaying/editing GFX and PGFX sections
in either binary or hexidecimal.</li>
in either binary or hexadecimal.</li>
<li><b>Use address relocation</b>: Corresponds to the DiStella '-r' option
(Relocate calls out of address range).</br>

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 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.7.1</center>
<center>Release 7.0</center>
<center><h2>Quick Navigation Guide</h2></center>
<br/>
@ -95,17 +95,17 @@
<td>Open settings</td>
</tr>
<tr>
<td>Button 7</td>
<td>Button 8</td>
<td>-</td>
<td>Rewind game</td>
</tr>
<tr>
<td>Button 8</td>
<td>Button 9</td>
<td>MODE</td>
<td>Select</td>
</tr>
<tr>
<td>Button 9</td>
<td>Button 10</td>
<td>RESET</td>
<td>Reset</td>
</tr>
@ -160,6 +160,21 @@
Button 2 or 6 close the menu without any action.
</td>
</tr>
<tr>
<td>Button 1 + Left</td>
<td>-</td>
<td>Display previous image</td>
</tr>
<tr>
<td>Button 1 + Right</td>
<td>-</td>
<td>Display next image</td>
</tr>
<tr>
<td>Button 1 + Up</td>
<td>-</td>
<td>Toggle image zoom</td>
</tr>
<tr>
<td>Button 2</td>
<td>SKILL P2</td>
@ -249,7 +264,7 @@
<td width="41%">This dialog is similar to the PC version's
<a href="index.html#CommandMenu"><b>Command Menu</b></a>, but with some
commands especially selected for the RetroN&nbsp;77.</td>
<td><p><img src="commandsmenu_r77.png"></p></td>
<td><p><img src="graphics/commandsmenu_r77.png"></p></td>
</tr>
</table>
</p>
@ -294,7 +309,7 @@
</tr>
</table>
</td>
<td><p><img src="basic_settings.png"></p></td>
<td><p><img src="graphics/basic_settings.png"></p></td>
</tr>
</table>
</p>

View File

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

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,7 +23,7 @@
class BankRomCheat : public Cheat
{
public:
BankRomCheat(OSystem& os, const string& name, const string& code);
BankRomCheat(OSystem& os, string_view name, string_view code);
~BankRomCheat() override = default;
bool enable() override;
@ -31,7 +31,7 @@ class BankRomCheat : public Cheat
void evaluate() override;
private:
std::array<uInt8, 16> savedRom;
std::array<uInt8, 16> savedRom{};
uInt16 address{0};
uInt8 value{0};
uInt8 count{0};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -25,9 +25,9 @@ class OSystem;
class Cheat
{
public:
Cheat(OSystem& osystem, const string& name, const string& code)
Cheat(OSystem& osystem, string_view name, string_view code)
: myOSystem{osystem},
myName{name == "" ? code : name},
myName{name.empty() ? code : name},
myCode{code} { }
virtual ~Cheat() = default;
@ -40,23 +40,6 @@ class Cheat
virtual void evaluate() = 0;
protected:
static uInt16 unhex(const string& hex)
{
int ret = 0;
for(const auto c: hex)
{
ret *= 16;
if(c >= '0' && c <= '9')
ret += c - '0';
else if(c >= 'A' && c <= 'F')
ret += c - 'A' + 10;
else
ret += c - 'a' + 10;
}
return ret;
}
protected:
OSystem& myOSystem;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -25,7 +25,6 @@
#include "Font.hxx"
#include "InputTextDialog.hxx"
#include "OSystem.hxx"
#include "Props.hxx"
#include "Widget.hxx"
#include "CheatCodeDialog.hxx"
@ -83,18 +82,18 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
// Inputbox which will pop up when adding/editing a cheat
StringList labels;
labels.push_back("Name ");
labels.push_back("Code (hex) ");
labels.emplace_back("Name ");
labels.emplace_back("Code (hex) ");
myCheatInput = make_unique<InputTextDialog>(this, font, labels, "Cheat code");
myCheatInput->setTarget(this);
// Add filtering for each textfield
EditableWidget::TextFilter f0 = [](char c) {
const EditableWidget::TextFilter f0 = [](char c) {
return isprint(c) && c != '\"' && c != ':';
};
myCheatInput->setTextFilter(f0, 0);
EditableWidget::TextFilter f1 = [](char c) {
const EditableWidget::TextFilter f1 = [](char c) {
return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9');
};
myCheatInput->setTextFilter(f1, 1);
@ -111,7 +110,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheatCodeDialog::~CheatCodeDialog()
CheatCodeDialog::~CheatCodeDialog() // NOLINT (we need an empty d'tor)
{
}
@ -128,14 +127,14 @@ void CheatCodeDialog::loadConfig()
for(const auto& c: list)
{
l.push_back(c->name());
b.push_back(bool(c->enabled()));
b.push_back(c->enabled());
}
myCheatList->setList(l, b);
// Redraw the list, auto-selecting the first item if possible
myCheatList->setSelected(l.size() > 0 ? 0 : -1);
myCheatList->setSelected(!l.empty() ? 0 : -1);
const bool enabled = (list.size() > 0);
const bool enabled = !list.empty();
myEditButton->setEnabled(enabled);
myRemoveButton->setEnabled(enabled);
}
@ -233,7 +232,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
{
const string& name = myCheatInput->getResult(0);
const string& code = myCheatInput->getResult(1);
if(instance().cheat().isValidCode(code))
if(CheatManager::isValidCode(code))
{
myCheatInput->close();
instance().cheat().add(name, code);
@ -250,7 +249,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
const string& code = myCheatInput->getResult(1);
const bool enable = myCheatList->getSelectedState();
const int idx = myCheatList->getSelected();
if(instance().cheat().isValidCode(code))
if(CheatManager::isValidCode(code))
{
myCheatInput->close();
instance().cheat().add(name, code, enable, idx);
@ -273,7 +272,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
{
const string& name = myCheatInput->getResult(0);
const string& code = myCheatInput->getResult(1);
if(instance().cheat().isValidCode(code))
if(CheatManager::isValidCode(code))
{
myCheatInput->close();
instance().cheat().addOneShot(name, code);

View File

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

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -16,7 +16,6 @@
//============================================================================
#include "OSystem.hxx"
#include "Console.hxx"
#include "Cheat.hxx"
#include "Settings.hxx"
#include "CheetahCheat.hxx"
@ -33,10 +32,10 @@ CheatManager::CheatManager(OSystem& osystem)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CheatManager::add(const string& name, const string& code,
bool CheatManager::add(string_view name, string_view code,
bool enable, int idx)
{
shared_ptr<Cheat> cheat = createCheat(name, code);
const shared_ptr<Cheat> cheat = createCheat(name, code);
if(!cheat)
return false;
@ -79,7 +78,7 @@ void CheatManager::remove(int idx)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::addPerFrame(const string& name, const string& code, bool enable)
void CheatManager::addPerFrame(string_view name, string_view code, bool enable)
{
// The actual cheat will always be in the main list; we look there first
shared_ptr<Cheat> cheat;
@ -93,8 +92,8 @@ void CheatManager::addPerFrame(const string& name, const string& code, bool enab
}
// Make sure there are no duplicates
bool found = false;
uInt32 i;
bool found{false};
uInt32 i{0};
for(i = 0; i < myPerFrameList.size(); ++i)
{
if(myPerFrameList[i]->code() == cheat->code())
@ -117,16 +116,16 @@ void CheatManager::addPerFrame(const string& name, const string& code, bool enab
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::addOneShot(const string& name, const string& code)
void CheatManager::addOneShot(string_view name, string_view code)
{
// Evaluate this cheat once, and then immediately discard it
shared_ptr<Cheat> cheat = createCheat(name, code);
const shared_ptr<Cheat> cheat = createCheat(name, code);
if(cheat)
cheat->evaluate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
shared_ptr<Cheat> CheatManager::createCheat(const string& name, const string& code) const
shared_ptr<Cheat> CheatManager::createCheat(string_view name, string_view code) const
{
if(!isValidCode(code))
return nullptr;
@ -136,14 +135,14 @@ shared_ptr<Cheat> CheatManager::createCheat(const string& name, const string& co
{
case 4: return make_shared<RamCheat>(myOSystem, name, code);
case 6: return make_shared<CheetahCheat>(myOSystem, name, code);
case 7: return make_shared<BankRomCheat>(myOSystem, name, code);
case 7: [[fallthrough]];
case 8: return make_shared<BankRomCheat>(myOSystem, name, code);
default: return nullptr;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::parse(const string& cheats)
void CheatManager::parse(string_view cheats)
{
StringList s;
string::size_type lastPos = cheats.find_first_not_of(',', 0);
@ -198,7 +197,7 @@ void CheatManager::parse(const string& cheats)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::enable(const string& code, bool enable)
void CheatManager::enable(string_view code, bool enable)
{
for(const auto& cheat: myCheatList)
{
@ -225,7 +224,7 @@ void CheatManager::loadCheatDatabase()
// Loop reading cheats
while(getline(in, line))
{
if(line.length() == 0)
if(line.empty())
continue;
const string::size_type one = line.find('\"', 0);
@ -256,14 +255,14 @@ void CheatManager::saveCheatDatabase()
stringstream out;
for(const auto& [md5, cheat]: myCheatMap)
out << "\"" << md5 << "\" " << "\"" << cheat << "\"" << endl;
out << "\"" << md5 << "\" " << "\"" << cheat << "\"\n";
try { myOSystem.cheatFile().write(out); }
catch(...) { return; }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::loadCheats(const string& md5sum)
void CheatManager::loadCheats(string_view md5sum)
{
myPerFrameList.clear();
myCheatList.clear();
@ -272,11 +271,11 @@ void CheatManager::loadCheats(const string& md5sum)
// Set up any cheatcodes that was on the command line
// (and remove the key from the settings, so they won't get set again)
const string& cheats = myOSystem.settings().getString("cheat");
if(cheats != "")
if(!cheats.empty())
myOSystem.settings().setValue("cheat", "");
const auto& iter = myCheatMap.find(md5sum);
if(iter == myCheatMap.end() && cheats == "")
if(iter == myCheatMap.end() && cheats.empty())
return;
// Remember the cheats for this ROM
@ -287,7 +286,7 @@ void CheatManager::loadCheats(const string& md5sum)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatManager::saveCheats(const string& md5sum)
void CheatManager::saveCheats(string_view md5sum)
{
ostringstream cheats;
for(uInt32 i = 0; i < myCheatList.size(); ++i)
@ -299,7 +298,7 @@ void CheatManager::saveCheats(const string& md5sum)
cheats << ",";
}
bool changed = cheats.str() != myCurrentCheat;
const bool changed = cheats.view() != myCurrentCheat;
// Only update the list if absolutely necessary
if(changed)
@ -311,8 +310,8 @@ void CheatManager::saveCheats(const string& md5sum)
myCheatMap.erase(iter);
// Add new entry only if there are any cheats defined
if(cheats.str() != "")
myCheatMap.emplace(md5sum, cheats.str());
if(!cheats.view().empty())
myCheatMap.emplace(md5sum, cheats.view());
}
// Update the dirty flag
@ -322,7 +321,7 @@ void CheatManager::saveCheats(const string& md5sum)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CheatManager::isValidCode(const string& code) const
bool CheatManager::isValidCode(string_view code)
{
for(const auto c: code)
if(!isxdigit(c))

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -38,6 +38,7 @@ class CheatManager
{
public:
explicit CheatManager(OSystem& osystem);
~CheatManager() = default;
/**
Adds the specified cheat to an internal list.
@ -49,7 +50,7 @@ class CheatManager
@return Whether the cheat was created and enabled.
*/
bool add(const string& name, const string& code,
bool add(string_view name, string_view code,
bool enable = true, int idx = -1);
/**
@ -68,7 +69,7 @@ class CheatManager
@param code The actual cheatcode
@param enable Add or remove the cheat to the per-frame list
*/
void addPerFrame(const string& name, const string& code, bool enable);
void addPerFrame(string_view name, string_view code, bool enable);
/**
Creates and enables a one-shot cheat. One-shot cheats are the
@ -78,7 +79,7 @@ class CheatManager
@param name Name of the cheat (not absolutely required)
@param code The actual cheatcode (in hex)
*/
void addOneShot(const string& name, const string& code);
void addOneShot(string_view name, string_view code);
/**
Enable/disabled the cheat specified by the given code.
@ -86,7 +87,7 @@ class CheatManager
@param code The actual cheatcode to search for
@param enable Enable/disable the cheat
*/
void enable(const string& code, bool enable);
void enable(string_view code, bool enable);
/**
Returns the game cheatlist.
@ -111,17 +112,17 @@ class CheatManager
/**
Load cheats for ROM with given MD5sum to cheatlist(s).
*/
void loadCheats(const string& md5sum);
void loadCheats(string_view md5sum);
/**
Saves cheats for ROM with given MD5sum to cheat map.
*/
void saveCheats(const string& md5sum);
void saveCheats(string_view md5sum);
/**
Checks if a code is valid.
*/
bool isValidCode(const string& code) const;
static bool isValidCode(string_view code);
private:
/**
@ -132,14 +133,14 @@ class CheatManager
@return The cheat (if was created), else nullptr.
*/
shared_ptr<Cheat> createCheat(const string& name, const string& code) const;
shared_ptr<Cheat> createCheat(string_view name, string_view code) const;
/**
Parses a list of cheats and adds/enables each one.
@param cheats Comma-separated list of cheats (without any names)
*/
void parse(const string& cheats);
void parse(string_view cheats);
private:
OSystem& myOSystem;
@ -147,7 +148,7 @@ class CheatManager
CheatList myCheatList;
CheatList myPerFrameList;
std::map<string,string> myCheatMap;
std::map<string,string, std::less<>> myCheatMap;
string myCheatFile;
// This is set each time a new cheat/ROM is loaded, for later

View File

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

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,7 +23,7 @@
class CheetahCheat : public Cheat
{
public:
CheetahCheat(OSystem& os, const string& name, const string& code);
CheetahCheat(OSystem& os, string_view name, string_view code);
~CheetahCheat() override = default;
bool enable() override;
@ -31,7 +31,7 @@ class CheetahCheat : public Cheat
void evaluate() override;
private:
std::array<uInt8, 16> savedRom;
std::array<uInt8, 16> savedRom{};
uInt16 address{0};
uInt8 value{0};
uInt8 count{0};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,10 +23,10 @@
#include "RamCheat.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
RamCheat::RamCheat(OSystem& os, string_view name, string_view code)
: Cheat(os, name, code),
address{static_cast<uInt16>(unhex(myCode.substr(0, 2)))},
value{static_cast<uInt8>(unhex(myCode.substr(2, 2)))}
address{static_cast<uInt16>(BSPF::stoi<16>(myCode.substr(0, 2)))},
value{static_cast<uInt8>(BSPF::stoi<16>(myCode.substr(2, 2)))}
{
}
@ -55,5 +55,5 @@ bool RamCheat::disable()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RamCheat::evaluate()
{
myOSystem.console().system().poke(address, value);
myOSystem.console().system().pokeOob(address, value);
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,7 +23,7 @@
class RamCheat : public Cheat
{
public:
RamCheat(OSystem& os, const string& name, const string& code);
RamCheat(OSystem& os, string_view name, string_view code);
~RamCheat() override = default;
bool enable() override;

View File

@ -7,8 +7,10 @@ MODULE_OBJS := \
src/cheat/BankRomCheat.o \
src/cheat/RamCheat.o
MODULE_TEST_OBJS =
MODULE_DIRS += \
src/cheat
# Include common rules
# Include common rules
include $(srcdir)/common.rules

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -29,16 +29,20 @@ AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo)
{
const uInt8 sampleSize = myIsStereo ? 2 : 1;
myFragmentBuffer = make_unique<Int16[]>(myFragmentSize * sampleSize * (capacity + 2));
myFragmentBuffer = make_unique<Int16[]>(
static_cast<size_t>(myFragmentSize) * sampleSize * (capacity + 2));
for (uInt32 i = 0; i < capacity; ++i)
myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() + i * sampleSize * myFragmentSize;
myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() +
static_cast<size_t>(myFragmentSize) * sampleSize * i;
myAllFragments[capacity] = myFirstFragmentForEnqueue =
myFragmentBuffer.get() + capacity * sampleSize * myFragmentSize;
myFragmentBuffer.get() + static_cast<size_t>(myFragmentSize) * sampleSize *
capacity;
myAllFragments[capacity + 1] = myFirstFragmentForDequeue =
myFragmentBuffer.get() + (capacity + 1) * sampleSize * myFragmentSize;
myFragmentBuffer.get() + static_cast<size_t>(myFragmentSize) * sampleSize *
(capacity + 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -50,7 +54,7 @@ uInt32 AudioQueue::capacity() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 AudioQueue::size() const
{
lock_guard<mutex> guard(myMutex);
const lock_guard<mutex> guard(myMutex);
return mySize;
}
@ -70,7 +74,7 @@ uInt32 AudioQueue::fragmentSize() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int16* AudioQueue::enqueue(Int16* fragment)
{
lock_guard<mutex> guard(myMutex);
const lock_guard<mutex> guard(myMutex);
Int16* newFragment = nullptr;
@ -83,7 +87,7 @@ Int16* AudioQueue::enqueue(Int16* fragment)
return newFragment;
}
const uInt8 capacity = static_cast<uInt8>(myFragmentQueue.size());
const auto capacity = static_cast<uInt8>(myFragmentQueue.size());
const uInt8 fragmentIndex = (myNextFragment + mySize) % capacity;
newFragment = myFragmentQueue.at(fragmentIndex);
@ -101,7 +105,7 @@ Int16* AudioQueue::enqueue(Int16* fragment)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int16* AudioQueue::dequeue(Int16* fragment)
{
lock_guard<mutex> guard(myMutex);
const lock_guard<mutex> guard(myMutex);
if (mySize == 0) return nullptr;
@ -124,7 +128,7 @@ Int16* AudioQueue::dequeue(Int16* fragment)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioQueue::closeSink(Int16* fragment)
{
lock_guard<mutex> guard(myMutex);
const lock_guard<mutex> guard(myMutex);
if (myFirstFragmentForDequeue && fragment)
throw runtime_error("attempt to return unknown buffer on closeSink");

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -24,7 +24,7 @@
#include "StaggeredLogger.hxx"
/**
This class implements a an audio queue that acts both like a ring buffer
This class implements an audio queue that acts both like a ring buffer
and a pool of audio fragments. The TIA emulation core fills a fragment
with samples and then returns it to the queue, receiving a new fragment
in return. The sound driver removes fragments for playback from the
@ -46,6 +46,7 @@ class AudioQueue
@param isStereo Whether samples are stereo or mono.
*/
AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo);
~AudioQueue() = default;
/**
Capacity getter.
@ -133,7 +134,6 @@ class AudioQueue
StaggeredLogger myOverflowLogger{"audio buffer overflow", Logger::Level::INFO};
private:
AudioQueue() = delete;
AudioQueue(const AudioQueue&) = delete;
AudioQueue(AudioQueue&&) = delete;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -35,11 +35,11 @@ namespace {
constexpr AudioSettings::ResamplingQuality normalizeResamplingQuality(int numericResamplingQuality)
{
return (
numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeightbour) &&
numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeighbour) &&
numericResamplingQuality <= static_cast<int>(AudioSettings::ResamplingQuality::lanczos_3)
) ? static_cast<AudioSettings::ResamplingQuality>(numericResamplingQuality) : AudioSettings::DEFAULT_RESAMPLING_QUALITY;
}
}
} // namespace
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AudioSettings::AudioSettings(Settings& settings)
@ -51,9 +51,10 @@ AudioSettings::AudioSettings(Settings& settings)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioSettings::normalize(Settings& settings)
{
int settingPreset = settings.getInt(SETTING_PRESET);
const int settingPreset = settings.getInt(SETTING_PRESET);
const Preset preset = normalizedPreset(settingPreset);
if (static_cast<int>(preset) != settingPreset) settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET));
if (static_cast<int>(preset) != settingPreset)
settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET));
switch (settings.getInt(SETTING_SAMPLE_RATE)) {
case 44100:
@ -80,18 +81,19 @@ void AudioSettings::normalize(Settings& settings)
break;
}
int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
const int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
if (settingBufferSize < 0 || settingBufferSize > MAX_BUFFER_SIZE) settings.setValue(SETTING_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
int settingHeadroom = settings.getInt(SETTING_HEADROOM);
const int settingHeadroom = settings.getInt(SETTING_HEADROOM);
if (settingHeadroom < 0 || settingHeadroom > MAX_HEADROOM) settings.setValue(SETTING_HEADROOM, DEFAULT_HEADROOM);
int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY);
const ResamplingQuality resamplingQuality = normalizeResamplingQuality(settingResamplingQuality);
const int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY);
const ResamplingQuality resamplingQuality =
normalizeResamplingQuality(settingResamplingQuality);
if (static_cast<int>(resamplingQuality) != settingResamplingQuality)
settings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(DEFAULT_RESAMPLING_QUALITY));
int settingVolume = settings.getInt(SETTING_VOLUME);
const int settingVolume = settings.getInt(SETTING_VOLUME);
if (settingVolume < 0 || settingVolume > 100) settings.setValue(SETTING_VOLUME, DEFAULT_VOLUME);
}
@ -186,7 +188,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
myPresetFragmentSize = 1024;
myPresetBufferSize = 6;
myPresetHeadroom = 5;
myPresetResamplingQuality = ResamplingQuality::nearestNeightbour;
myPresetResamplingQuality = ResamplingQuality::nearestNeighbour;
break;
case Preset::highQualityMediumLag:

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -26,7 +26,7 @@ class AudioSettings
{
public:
enum class Preset {
enum class Preset: uInt8 {
custom = 1,
lowQualityMediumLag = 2,
highQualityMediumLag = 3,
@ -34,23 +34,23 @@ class AudioSettings
ultraQualityMinimalLag = 5
};
enum class ResamplingQuality {
nearestNeightbour = 1,
lanczos_2 = 2,
lanczos_3 = 3
enum class ResamplingQuality: uInt8 {
nearestNeighbour = 1,
lanczos_2 = 2,
lanczos_3 = 3
};
static constexpr const char* SETTING_PRESET = "audio.preset";
static constexpr const char* SETTING_SAMPLE_RATE = "audio.sample_rate";
static constexpr const char* SETTING_FRAGMENT_SIZE = "audio.fragment_size";
static constexpr const char* SETTING_BUFFER_SIZE = "audio.buffer_size";
static constexpr const char* SETTING_HEADROOM = "audio.headroom";
static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
static constexpr const char* SETTING_STEREO = "audio.stereo";
static constexpr const char* SETTING_VOLUME = "audio.volume";
static constexpr const char* SETTING_DEVICE = "audio.device";
static constexpr const char* SETTING_ENABLED = "audio.enabled";
static constexpr const char* SETTING_DPC_PITCH = "audio.dpc_pitch";
static constexpr string_view SETTING_PRESET = "audio.preset";
static constexpr string_view SETTING_SAMPLE_RATE = "audio.sample_rate";
static constexpr string_view SETTING_FRAGMENT_SIZE = "audio.fragment_size";
static constexpr string_view SETTING_BUFFER_SIZE = "audio.buffer_size";
static constexpr string_view SETTING_HEADROOM = "audio.headroom";
static constexpr string_view SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
static constexpr string_view SETTING_STEREO = "audio.stereo";
static constexpr string_view SETTING_VOLUME = "audio.volume";
static constexpr string_view SETTING_DEVICE = "audio.device";
static constexpr string_view SETTING_ENABLED = "audio.enabled";
static constexpr string_view SETTING_DPC_PITCH = "audio.dpc_pitch";
static constexpr Preset DEFAULT_PRESET = Preset::highQualityMediumLag;
static constexpr uInt32 DEFAULT_SAMPLE_RATE = 44100;
@ -127,7 +127,7 @@ class AudioSettings
private:
Settings& mySettings;
Settings& mySettings; // NOLINT: we want a reference here
Preset myPreset{Preset::custom};
@ -135,7 +135,7 @@ class AudioSettings
uInt32 myPresetFragmentSize{0};
uInt32 myPresetBufferSize{0};
uInt32 myPresetHeadroom{0};
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeightbour};
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeighbour};
bool myIsPersistent{true};
};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -24,7 +24,7 @@ string Base::toString(int value, Common::Base::Fmt outputBase)
{
static char vToS_buf[32]; // NOLINT : One place where C-style is acceptable
if(outputBase == Base::Fmt::_DEFAULT)
if(outputBase == Base::Fmt::DEFAULT)
outputBase = myDefaultBase;
switch(outputBase)
@ -47,74 +47,83 @@ string Base::toString(int value, Common::Base::Fmt outputBase)
case Base::Fmt::_10: // base 10: 3 or 5 bytes (depending on value)
if(value > -0x100 && value < 0x100)
std::snprintf(vToS_buf, 5, "%3d", static_cast<Int16>(value));
std::ignore = std::snprintf(vToS_buf, 5, "%3d", static_cast<Int16>(value));
else
std::snprintf(vToS_buf, 6, "%5d", value);
std::ignore = std::snprintf(vToS_buf, 6, "%5d", value);
break;
case Base::Fmt::_10_02: // base 10: 2 digits (with leading zero)
std::snprintf(vToS_buf, 3, "%02d", value);
std::ignore = std::snprintf(vToS_buf, 3, "%02d", value);
break;
case Base::Fmt::_10_3: // base 10: 3 digits
std::snprintf(vToS_buf, 4, "%3d", value);
std::ignore = std::snprintf(vToS_buf, 4, "%3d", value);
break;
case Base::Fmt::_10_4: // base 10: 4 digits
std::snprintf(vToS_buf, 5, "%4d", value);
std::ignore = std::snprintf(vToS_buf, 5, "%4d", value);
break;
case Base::Fmt::_10_5: // base 10: 5 digits
std::snprintf(vToS_buf, 6, "%5d", value);
std::ignore = std::snprintf(vToS_buf, 6, "%5d", value);
break;
case Base::Fmt::_10_6: // base 10: 6 digits
std::snprintf(vToS_buf, 7, "%6d", value);
std::ignore = std::snprintf(vToS_buf, 7, "%6d", value);
break;
case Base::Fmt::_10_8: // base 10: 8 digits
std::snprintf(vToS_buf, 9, "%8d", value);
std::ignore = std::snprintf(vToS_buf, 9, "%8d", value);
break;
case Base::Fmt::_16_1: // base 16: 1 byte wide
std::snprintf(vToS_buf, 2, hexUppercase() ? "%1X" : "%1x", value);
std::ignore = std::snprintf(
vToS_buf, 2, hexUppercase() ? "%1X" : "%1x", value);
break;
case Base::Fmt::_16_2: // base 16: 2 bytes wide
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
std::ignore = std::snprintf(
vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
break;
case Base::Fmt::_16_2_2:
std::snprintf(vToS_buf, 6, hexUppercase() ? "%02X.%02X" : "%02x.%02x",
value >> 8, value & 0xff );
std::ignore = std::snprintf(
vToS_buf, 6, hexUppercase() ? "%02X.%02X" : "%02x.%02x",
value >> 8, value & 0xff );
break;
case Base::Fmt::_16_3_2:
std::snprintf(vToS_buf, 7, hexUppercase() ? "%03X.%02X" : "%03x.%02x",
value >> 8, value & 0xff );
std::ignore = std::snprintf(
vToS_buf, 7, hexUppercase() ? "%03X.%02X" : "%03x.%02x",
value >> 8, value & 0xff );
break;
case Base::Fmt::_16_4: // base 16: 4 bytes wide
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
std::ignore = std::snprintf(
vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
break;
case Base::Fmt::_16_8: // base 16: 8 bytes wide
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
std::ignore = std::snprintf(
vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
break;
case Base::Fmt::_16: // base 16: 2, 4, 8 bytes (depending on value)
default:
if(value < 0x100)
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
std::ignore = std::snprintf(
vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
else if(value < 0x10000)
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
std::ignore = std::snprintf(
vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
else
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
std::ignore = std::snprintf(
vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
break;
}
return string(vToS_buf);
return {vToS_buf};
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Base::Fmt Base::myDefaultBase = Base::Fmt::_16;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex;
std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex; // NOLINT
} // Namespace Common
} // namespace Common

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -38,7 +38,7 @@ class Base
// The base to use for conversion from integers to strings
// Note that the actual number of places will be determined by
// the magnitude of the value itself in the general case
enum class Fmt {
enum class Fmt: uInt8 {
_16, // base 16: 2, 4, 8 bytes (depending on value)
_16_1, // base 16: 1 byte wide
_16_2, // base 16: 2 bytes wide
@ -56,7 +56,7 @@ class Base
_2, // base 2: 8 or 16 bits (depending on value)
_2_8, // base 2: 1 byte (8 bits) wide
_2_16, // base 2: 2 bytes (16 bits) wide
_DEFAULT
DEFAULT
};
public:
@ -72,31 +72,31 @@ class Base
static bool hexUppercase() { return myHexflags & std::ios_base::uppercase; }
/** Output HEX digits in 0.5/1/2/4 byte format */
static inline std::ostream& HEX1(std::ostream& os) {
static std::ostream& HEX1(std::ostream& os) {
os.flags(myHexflags);
return os << std::setw(1);
}
static inline std::ostream& HEX2(std::ostream& os) {
static std::ostream& HEX2(std::ostream& os) {
os.flags(myHexflags);
return os << std::setw(2) << std::setfill('0');
}
static inline std::ostream& HEX3(std::ostream& os)
static std::ostream& HEX3(std::ostream& os)
{
os.flags(myHexflags);
return os << std::setw(3) << std::setfill('0');
}
static inline std::ostream& HEX4(std::ostream& os) {
static std::ostream& HEX4(std::ostream& os) {
os.flags(myHexflags);
return os << std::setw(4) << std::setfill('0');
}
static inline std::ostream& HEX8(std::ostream& os) {
static std::ostream& HEX8(std::ostream& os) {
os.flags(myHexflags);
return os << std::setw(8) << std::setfill('0');
}
/** Convert integer to a string in the given base format */
static string toString(int value,
Common::Base::Fmt outputBase = Common::Base::Fmt::_DEFAULT);
Common::Base::Fmt outputBase = Common::Base::Fmt::DEFAULT);
private:
// Default format to use when none is specified
@ -108,6 +108,7 @@ class Base
private:
// Following constructors and assignment operators not supported
Base() = delete;
~Base() = delete;
Base(const Base&) = delete;
Base(Base&&) = delete;
Base& operator=(const Base&) = delete;

252
src/common/Bezel.cxx Normal file
View File

@ -0,0 +1,252 @@
//============================================================================
//
// 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-2025 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 <cmath>
#include "OSystem.hxx"
#include "Console.hxx"
#include "EventHandler.hxx"
#include "FBSurface.hxx"
#include "PNGLibrary.hxx"
#include "PropsSet.hxx"
#include "Bezel.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Bezel::Bezel(OSystem& osystem)
: myOSystem{osystem},
myFB{osystem.frameBuffer()}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Bezel::getName(const string& path, const Properties& props)
{
string imageName;
int index = 1; // skip property name
do
{
imageName = getName(props, index);
if(imageName != EmptyString)
{
// Note: JPG does not support transparency
const string imagePath = path + imageName + ".png";
const FSNode node(imagePath);
if(node.exists())
break;
}
} while(index != -1);
return imageName;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Bezel::getName(const Properties& props, int& index)
{
if(++index == 1)
return props.get(PropType::Bezel_Name);
// Try to generate bezel name from cart name
const string& cartName = props.get(PropType::Cart_Name);
size_t pos = cartName.find_first_of('(');
if(pos == std::string::npos)
pos = cartName.length() + 1;
if(index < 10 && pos != std::string::npos && pos > 0)
{
// The following suffixes are from "The Official No-Intro Convention",
// covering all used combinations by "The Bezel Project" (except single ones)
// (Unl) = unlicensed (Homebrews)
const std::array<string, 8> suffixes = {
" (USA)", " (USA) (Proto)", " (USA) (Unl)", " (USA) (Hack)",
" (Europe)", " (Germany)", " (France) (Unl)", " (Australia)"
};
return cartName.substr(0, pos - 1) + suffixes[index - 2];
}
if(index == 10)
{
return "Atari-2600";
}
if(index == 11)
{
index = -1;
return "default";
}
return "";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Bezel::getName(int& index) const
{
return getName(myOSystem.console().properties(), index);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 Bezel::borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const
{
uInt32 *pixels{nullptr}, pitch{0};
mySurface->basePtr(pixels, pitch);
pixels += x + y * pitch;
for(uInt32 i = 0; i < size; ++i, pixels += step)
{
uInt8 r{0}, g{0}, b{0}, a{0};
myFB.getRGBA(*pixels, &r, &g, &b, &a);
if(a < 255) // transparent pixel?
return i;
}
return size - 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Bezel::load()
{
const Settings& settings = myOSystem.settings();
bool isValid = false;
string imageName;
#ifdef IMAGE_SUPPORT
const bool show = myOSystem.eventHandler().inTIAMode() &&
settings.getBool("bezel.show") &&
(settings.getBool("fullscreen") ||
settings.getBool("bezel.windowed"));
if(show)
{
if(!mySurface)
mySurface = myFB.allocateSurface(1, 1); // dummy size
try
{
const string& path = myOSystem.bezelDir().getPath();
VariantList metaData;
int index = 0;
do
{
imageName = getName(index);
if(imageName != EmptyString)
{
// Note: JPG does not support transparency
const string imagePath = path + imageName + ".png";
const FSNode node(imagePath);
if(node.exists())
{
isValid = true;
myOSystem.png().loadImage(imagePath, *mySurface, metaData);
break;
}
}
} while(index != -1);
}
catch(const runtime_error&) { cerr << "ERROR: Bezel load\n"; }
}
#else
const bool show = false;
#endif
if(isValid)
{
const Int32 w = mySurface->width();
const Int32 h = mySurface->height();
uInt32 top{0}, bottom{0}, left{0}, right{0};
if(settings.getBool("bezel.win.auto"))
{
// Determine transparent window inside bezel image
const uInt32 xCenter = w >> 1;
top = borderSize(xCenter, 0, h, w);
bottom = h - 1 - borderSize(xCenter, h - 1, h, -w);
const uInt32 yCenter = (bottom + top) >> 1;
left = borderSize(0, yCenter, w, 1);
right = w - 1 - borderSize(w - 1, yCenter, w, -1);
}
else
{
// BP: 13, 13, 0, 0%
// HY: 12, 12, 0, 0%
// P1: 25, 25, 11, 22%
// P2: 23, 23, 7, 20%
left = std::min(w - 1, static_cast<Int32>(w * settings.getInt("bezel.win.left") / 100. + .5)); // NOLINT
right = w - 1 - std::min(w - 1, static_cast<Int32>(w * settings.getInt("bezel.win.right") / 100. + .5)); // NOLINT
top = std::min(h - 1, static_cast<Int32>(h * settings.getInt("bezel.win.top") / 100. + .5)); // NOLINT
bottom = h - 1 - std::min(h - 1, static_cast<Int32>(h * settings.getInt("bezel.win.bottom") / 100. + .5)); // NOLINT
}
//cerr << (int)(right - left + 1) << " x " << (int)(bottom - top + 1) << " = "
// << double((int)(right - left + 1)) / double((int)(bottom - top + 1));
// Disable bezel is no transparent window was found
if(left < right && top < bottom)
myInfo = Info(Common::Size(w, h), Common::Rect(left, top, right, bottom));
else
{
if(mySurface)
myFB.deallocateSurface(mySurface);
mySurface = nullptr;
myInfo = Info();
myFB.showTextMessage("Invalid bezel image ('" + imageName + "')!");
isValid = false;
}
}
else
{
myInfo = Info();
if(show)
myFB.showTextMessage("No bezel image found");
}
return isValid;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Bezel::apply()
{
if(isShown())
{
const uInt32 bezelW =
std::min(myFB.screenSize().w,
static_cast<uInt32>(std::round(myFB.imageRect().w() * myInfo.ratioW())));
const uInt32 bezelH =
std::min(myFB.screenSize().h,
static_cast<uInt32>(std::round(myFB.imageRect().h() * myInfo.ratioH())));
// Position and scale bezel
mySurface->setDstSize(bezelW, bezelH);
mySurface->setDstPos((myFB.screenSize().w - bezelW) / 2, // center
(myFB.screenSize().h - bezelH) / 2);
mySurface->setScalingInterpolation(ScalingInterpolation::sharp);
// Note: Variable bezel window positions are handled in VideoModeHandler::Mode
// Enable blending to allow overlaying the bezel over the TIA output
mySurface->attributes().blending = true;
mySurface->attributes().blendalpha = 100;
mySurface->applyAttributes();
mySurface->setVisible(true);
}
else
if(mySurface)
mySurface->setVisible(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Bezel::render()
{
if(mySurface)
mySurface->render();
}

151
src/common/Bezel.hxx Normal file
View File

@ -0,0 +1,151 @@
//============================================================================
//
// 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-2025 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 BEZEL_HXX
#define BEZEL_HXX
class OSystem;
class FBSurface;
class FrameBuffer;
class Properties;
#include "Rect.hxx"
/**
This class handles the bezels.
Bezels are loaded using a file name which is either a bezel name property or
is autogenerated from the cart name property. The bezels can be any size and
their transparent emulation window can be at any position. The position of
the window can be determined automatically.
+--------------------------------------+
| | display.h
+--------------------------------------+
| |
| +---------------+ |
| | window | |
| | | |
| | tia.h * zoom | |
| | | | bezel.h * zoom
| | | |
| +---------------+ |
| |
+--------------------------------------+ size
| |
+--------------------------------------+
The bezel and window sizes and their ratios are used for correct scaling.
@author Thomas Jentzsch
*/
class Bezel
{
public:
explicit Bezel(OSystem& osystem);
~Bezel() = default;
struct Info
{
private:
bool _isShown{false}; // Is bezel shown?
Common::Size _size{1, 1}; // Bezel size
Common::Rect _window{1, 1}; // Area of transparent TIA window inside bezel
public:
explicit Info() = default;
explicit Info(Common::Size size, Common::Rect window)
: _isShown{true}, _size{size}, _window{window} { }
bool isShown() const { return _isShown; }
Common::Size size() const { return _size; }
Common::Rect window() const { return _window; }
// Ratios between bezel sizes and TIA window sizes
double ratioW() const { return static_cast<double>(size().w) / window().w(); }
double ratioH() const { return static_cast<double>(size().h) / window().h(); }
};
// Structure access methods
const Info& info() const { return myInfo; }
bool isShown() const { return myInfo.isShown(); }
Common::Size size() const { return myInfo.size(); }
Common::Rect window() const { return myInfo.window(); }
// Ratio between bezel size and TIA window size
double ratioW() const { return myInfo.ratioW(); }
double ratioH() const { return myInfo.ratioH(); }
/*
Calculate size of a bezel border.
*/
uInt32 borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const;
/*
Load the bezel.
*/
bool load();
/*
Display scaled bezel.
*/
void apply();
/*
Render bezel surface
*/
void render();
/*
Generate bezel file name.
*/
static string getName(const string& path, const Properties& props);
private:
/*
Generate bezel file name.
*/
static string getName(const Properties& props, int& index);
/*
Generate bezel file name.
*/
string getName(int& index) const;
private:
// The parent system for the bezel
OSystem& myOSystem;
// Pointer to the FrameBuffer object
FrameBuffer& myFB;
// The bezel surface which blends over the TIA surface
shared_ptr<FBSurface> mySurface;
// Bezel info structure
Info myInfo;
private:
// Following constructors and assignment operators not supported
Bezel() = delete;
Bezel(const Bezel&) = delete;
Bezel(Bezel&&) = delete;
Bezel& operator=(const Bezel&) = delete;
Bezel& operator=(Bezel&&) = delete;
};
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,6 +23,8 @@
#include "Settings.hxx"
#include "StateManager.hxx"
#include "TIA.hxx"
#include "Cart.hxx"
#include "CartELF.hxx"
#include "DevSettingsHandler.hxx"
@ -41,12 +43,17 @@ void DevSettingsHandler::loadSettings(SettingsSet set)
myFrameStats[set] = settings.getBool(prefix + "stats");
myDetectedInfo[set] = settings.getBool(prefix + "detectedinfo");
// AtariVox/SaveKey/PlusROM access
myExternAccess[set] = settings.getBool(prefix + "extaccess");
myConsole[set] = settings.getString(prefix + "console") == "7800" ? 1 : 0;
myPlusROM[set] = devSettings ? settings.getBool("dev.plusroms.on") : true;
// Randomization
myRandomBank[set] = settings.getBool(prefix + "bankrandom");
myRandomizeTIA[set] = settings.getBool(prefix + "tiarandom");
myRandomizeRAM[set] = settings.getBool(prefix + "ramrandom");
myRandomizeCPU[set] = settings.getString(prefix + "cpurandom");
// Random hotspot peeks
myRandomHotspots[set] = devSettings ? settings.getBool("dev.hsrandom") : false;
// Undriven TIA pins
myUndrivenPins[set] = devSettings ? settings.getBool("dev.tiadriven") : false;
#ifdef DEBUGGER_SUPPORT
@ -57,14 +64,16 @@ void DevSettingsHandler::loadSettings(SettingsSet set)
#endif
// Thumb ARM emulation exception
myThumbException[set] = devSettings ? settings.getBool("dev.thumb.trapfatal") : false;
// AtariVox/SaveKey/PlusROM access
myExternAccess[set] = settings.getBool(prefix + "extaccess");
myArmSpeed[set] = devSettings ? settings.getInt("dev.arm.mips") : CartridgeELF::MIPS_MAX;
// TIA tab
myTIAType[set] = devSettings ? settings.getString("dev.tia.type") : "standard";
myPlInvPhase[set] = devSettings ? settings.getBool("dev.tia.plinvphase") : false;
myMsInvPhase[set] = devSettings ? settings.getBool("dev.tia.msinvphase") : false;
myBlInvPhase[set] = devSettings ? settings.getBool("dev.tia.blinvphase") : false;
myPlLateHMove[set] = devSettings ? settings.getBool("dev.tia.pllatehmove") : false;
myMsLateHMove[set] = devSettings ? settings.getBool("dev.tia.mslatehmove") : false;
myBlLateHMove[set] = devSettings ? settings.getBool("dev.tia.bllatehmove") : false;
myPFBits[set] = devSettings ? settings.getBool("dev.tia.delaypfbits") : false;
myPFColor[set] = devSettings ? settings.getBool("dev.tia.delaypfcolor") : false;
myPFScore[set] = devSettings ? settings.getBool("dev.tia.pfscoreglitch") : false;
@ -110,6 +119,8 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
if(devSettings)
{
settings.setValue("dev.plusroms.on", myPlusROM[set]);
settings.setValue("dev.hsrandom", myRandomHotspots[set]);
// Undriven TIA pins
settings.setValue("dev.tiadriven", myUndrivenPins[set]);
#ifdef DEBUGGER_SUPPORT
@ -120,6 +131,7 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
#endif
// Thumb ARM emulation exception
settings.setValue("dev.thumb.trapfatal", myThumbException[set]);
settings.setValue("dev.arm.mips", myArmSpeed[set]);
}
// AtariVox/SaveKey/PlusROM access
@ -134,6 +146,9 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
settings.setValue("dev.tia.plinvphase", myPlInvPhase[set]);
settings.setValue("dev.tia.msinvphase", myMsInvPhase[set]);
settings.setValue("dev.tia.blinvphase", myBlInvPhase[set]);
settings.setValue("dev.tia.pllatehmove", myPlLateHMove[set]);
settings.setValue("dev.tia.mslatehmove", myMsLateHMove[set]);
settings.setValue("dev.tia.bllatehmove", myBlLateHMove[set]);
settings.setValue("dev.tia.delaypfbits", myPFBits[set]);
settings.setValue("dev.tia.delaypfcolor", myPFColor[set]);
settings.setValue("dev.tia.pfscoreglitch", myPFScore[set]);
@ -168,7 +183,9 @@ void DevSettingsHandler::applySettings(SettingsSet set)
if(myOSystem.hasConsole())
{
myOSystem.console().cartridge().enableRandomHotspots(myRandomHotspots[set]);
myOSystem.console().tia().driveUnusedPinsRandom(myUndrivenPins[set]);
myOSystem.console().cartridge().enablePlusROM(myPlusROM[set]);
// Notes:
// - thumb exceptions not updated, because set in cart constructor
// - other missing settings are used on-the-fly
@ -189,6 +206,9 @@ void DevSettingsHandler::applySettings(SettingsSet set)
myOSystem.console().tia().setPlInvertedPhaseClock(myPlInvPhase[set]);
myOSystem.console().tia().setMsInvertedPhaseClock(myMsInvPhase[set]);
myOSystem.console().tia().setBlInvertedPhaseClock(myBlInvPhase[set]);
myOSystem.console().tia().setPlShortLateHMove(myPlLateHMove[set]);
myOSystem.console().tia().setMsShortLateHMove(myMsLateHMove[set]);
myOSystem.console().tia().setBlShortLateHMove(myBlLateHMove[set]);
myOSystem.console().tia().setPFBitsDelay(myPFBits[set]);
myOSystem.console().tia().setPFColorDelay(myPFColor[set]);
myOSystem.console().tia().setPFScoreGlitch(myPFScore[set]);

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -21,6 +21,7 @@
class OSystem;
#include <array>
#include "bspf.hxx"
/**
This class takes care of developer settings sets.
@ -30,13 +31,14 @@ class OSystem;
class DevSettingsHandler
{
public:
enum SettingsSet {
enum SettingsSet: uInt8 {
player,
developer,
numSets
};
explicit DevSettingsHandler(OSystem& osystem);
~DevSettingsHandler() = default;
void loadSettings(SettingsSet set);
void saveSettings(SettingsSet set);
@ -45,42 +47,48 @@ class DevSettingsHandler
protected:
OSystem& myOSystem;
// Emulator sets
std::array<bool, numSets> myFrameStats;
std::array<bool, numSets> myDetectedInfo;
std::array<bool, numSets> myExternAccess;
std::array<int, numSets> myConsole;
std::array<bool, numSets> myRandomBank;
std::array<bool, numSets> myRandomizeTIA;
std::array<bool, numSets> myRandomizeRAM;
std::array<string, numSets> myRandomizeCPU;
std::array<bool, numSets> myColorLoss;
std::array<bool, numSets> myTVJitter;
std::array<int, numSets> myTVJitterSense;
std::array<int, numSets> myTVJitterRec;
std::array<bool, numSets> myDebugColors;
std::array<bool, numSets> myUndrivenPins;
std::array<bool, numSets> myFrameStats{};
std::array<bool, numSets> myDetectedInfo{};
std::array<bool, numSets> myExternAccess{};
std::array<int, numSets> myConsole{};
std::array<int, numSets> myPlusROM{};
std::array<bool, numSets> myRandomBank{};
std::array<bool, numSets> myRandomizeTIA{};
std::array<bool, numSets> myRandomizeRAM{};
std::array<string, numSets> myRandomizeCPU{};
std::array<bool, numSets> myColorLoss{};
std::array<bool, numSets> myTVJitter{};
std::array<int, numSets> myTVJitterSense{};
std::array<int, numSets> myTVJitterRec{};
std::array<bool, numSets> myDebugColors{};
std::array<bool, numSets> myRandomHotspots{};
std::array<bool, numSets> myUndrivenPins{};
#ifdef DEBUGGER_SUPPORT
std::array<bool, numSets> myRWPortBreak;
std::array<bool, numSets> myWRPortBreak;
std::array<bool, numSets> myRWPortBreak{};
std::array<bool, numSets> myWRPortBreak{};
#endif
std::array<bool, numSets> myThumbException;
std::array<bool, numSets> myThumbException{};
std::array<int, numSets> myArmSpeed{};
// TIA sets
std::array<string, numSets> myTIAType;
std::array<bool, numSets> myPlInvPhase;
std::array<bool, numSets> myMsInvPhase;
std::array<bool, numSets> myBlInvPhase;
std::array<bool, numSets> myPFBits;
std::array<bool, numSets> myPFColor;
std::array<bool, numSets> myPFScore;
std::array<bool, numSets> myBKColor;
std::array<bool, numSets> myPlSwap;
std::array<bool, numSets> myBlSwap;
std::array<string, numSets> myTIAType{};
std::array<bool, numSets> myPlInvPhase{};
std::array<bool, numSets> myMsInvPhase{};
std::array<bool, numSets> myBlInvPhase{};
std::array<bool, numSets> myPlLateHMove{};
std::array<bool, numSets> myMsLateHMove{};
std::array<bool, numSets> myBlLateHMove{};
std::array<bool, numSets> myPFBits{};
std::array<bool, numSets> myPFColor{};
std::array<bool, numSets> myPFScore{};
std::array<bool, numSets> myBKColor{};
std::array<bool, numSets> myPlSwap{};
std::array<bool, numSets> myBlSwap{};
// States sets
std::array<bool, numSets> myTimeMachine;
std::array<int, numSets> myStateSize;
std::array<int, numSets> myUncompressed;
std::array<string, numSets> myStateInterval;
std::array<string, numSets> myStateHorizon;
std::array<bool, numSets> myTimeMachine{};
std::array<int, numSets> myStateSize{};
std::array<int, numSets> myUncompressed{};
std::array<string, numSets> myStateInterval{};
std::array<string, numSets> myStateHorizon{};
private:
void handleEnableDebugColors(bool enable);

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -30,9 +30,10 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
#ifdef GUI_SUPPORT
{
ostringstream buf;
myQwertz = int{'y'} == static_cast<int>(SDL_GetKeyFromScancode(SDL_Scancode(KBDK_Z)));
myQwertz = int{'y'} == static_cast<int>
(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(KBDK_Z)));
buf << "Keyboard: " << (myQwertz ? "QWERTZ" : "QWERTY");
Logger::debug(buf.str());
Logger::debug(buf.view());
}
#endif
@ -40,8 +41,9 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
ostringstream buf;
buf << "ERROR: Couldn't initialize SDL joystick support: " << SDL_GetError() << endl;
Logger::error(buf.str());
buf << "ERROR: Couldn't initialize SDL joystick support: "
<< SDL_GetError() << '\n';
Logger::error(buf.view());
}
Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK");
#endif
@ -123,25 +125,29 @@ void EventHandlerSDL2::pollEvent()
case SDL_MOUSEBUTTONUP:
{
// ToDo: check support of more buttons and double-click
MouseButton b{MouseButton::NONE};
switch(myEvent.button.button)
{
case SDL_BUTTON_LEFT:
handleMouseButtonEvent(MouseButton::LEFT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
myEvent.button.x, myEvent.button.y);
b = MouseButton::LEFT;
break;
case SDL_BUTTON_RIGHT:
handleMouseButtonEvent(MouseButton::RIGHT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
myEvent.button.x, myEvent.button.y);
b = MouseButton::RIGHT;
break;
case SDL_BUTTON_MIDDLE:
b = MouseButton::MIDDLE;
break;
default:
break;
}
handleMouseButtonEvent(b, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
myEvent.button.x, myEvent.button.y);
break;
}
case SDL_MOUSEWHEEL:
{
int x, y;
int x{0}, y{0};
SDL_GetMouseState(&x, &y); // we need mouse position too
if(myEvent.wheel.y < 0)
handleMouseButtonEvent(MouseButton::WHEELDOWN, true, x, y);
@ -259,6 +265,7 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
{
ASSERT_MAIN_THREAD;
// NOLINTNEXTLINE: we want to initialize here, not in the member list
myStick = SDL_JoystickOpen(idx);
if(myStick)
{
@ -267,7 +274,7 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
// it also appends " #x", where x seems to vary. Obviously this wreaks
// havoc with the idea that a joystick will always have the same name.
// So we truncate the number.
const char* sdlname = SDL_JoystickName(myStick);
const char* const sdlname = SDL_JoystickName(myStick);
const string& desc = BSPF::startsWithIgnoreCase(sdlname, "XInput Controller")
? "XInput Controller" : sdlname;

View File

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

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -17,7 +17,6 @@
#include <cmath>
#include "SDL_lib.hxx"
#include "bspf.hxx"
#include "Logger.hxx"
@ -84,7 +83,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
myNumDisplays = SDL_GetNumVideoDisplays();
// First get the maximum fullscreen desktop resolution
SDL_DisplayMode display;
SDL_DisplayMode display{};
for(int i = 0; i < myNumDisplays; ++i)
{
SDL_GetDesktopDisplayMode(i, &display);
@ -97,8 +96,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
s << "Supported video modes (" << numModes << ") for display " << i
<< " (" << SDL_GetDisplayName(i) << "):";
string lastRes = "";
string lastRes;
for(int m = 0; m < numModes; ++m)
{
SDL_DisplayMode mode;
@ -107,11 +105,11 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
SDL_GetDisplayMode(i, m, &mode);
res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
if(lastRes != res.str())
if(lastRes != res.view())
{
Logger::debug(s.str());
Logger::debug(s.view());
s.str("");
lastRes = res.str();
lastRes = res.view();
s << " " << lastRes << ": ";
}
s << mode.refresh_rate << "Hz";
@ -120,7 +118,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
else
s << " ";
}
Logger::debug(s.str());
Logger::debug(s.view());
}
// Now get the maximum windowed desktop resolution
@ -135,7 +133,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
SDL_DestroyWindow(tmpWindow);
}
SDL_Rect r;
SDL_Rect r{};
for(int i = 0; i < myNumDisplays; ++i)
{
// Display bounds minus dock
@ -157,13 +155,15 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
string stellaName;
};
// Create name map for all currently known SDL renderers
static const std::array<RenderName, 6> RENDERER_NAMES = {{
{ "direct3d", "Direct3D" },
{ "metal", "Metal" },
{ "opengl", "OpenGL" },
{ "opengles", "OpenGLES" },
{ "opengles2", "OpenGLES2" },
{ "software", "Software" }
static const std::array<RenderName, 8> RENDERER_NAMES = {{
{ "direct3d", "Direct3D" },
{ "direct3d11", "Direct3D 11" },
{ "direct3d12", "Direct3D 12" },
{ "metal", "Metal" },
{ "opengl", "OpenGL" },
{ "opengles", "OpenGL ES" },
{ "opengles2", "OpenGL ES 2" },
{ "software", "Software" }
}};
const int numDrivers = SDL_GetNumRenderDrivers();
@ -174,11 +174,11 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
{
// Map SDL names into nicer Stella names (if available)
bool found = false;
for(size_t j = 0; j < RENDERER_NAMES.size(); ++j)
for(const auto& render: RENDERER_NAMES)
{
if(RENDERER_NAMES[j].sdlName == info.name)
if(render.sdlName == info.name)
{
VarList::push_back(renderers, RENDERER_NAMES[j].stellaName, info.name);
VarList::push_back(renderers, render.stellaName, info.name);
found = true;
break;
}
@ -261,7 +261,7 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
}
#ifdef ADAPTABLE_REFRESH_SUPPORT
SDL_DisplayMode adaptedSdlMode;
SDL_DisplayMode adaptedSdlMode{};
const int gameRefreshRate =
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
const bool shouldAdapt = fullScreen
@ -284,11 +284,12 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
if(myWindow)
{
const int d = SDL_GetWindowDisplayIndex(myWindow);
int w, h;
int w{0}, h{0};
SDL_GetWindowSize(myWindow, &w, &h);
if(d != displayIndex || static_cast<uInt32>(w) != mode.screenS.w ||
static_cast<uInt32>(h) != mode.screenS.h || adaptRefresh)
if(d != displayIndex ||
std::cmp_not_equal(w, mode.screenS.w) ||
std::cmp_not_equal(h, mode.screenS.h) || adaptRefresh)
{
// Renderer has to be destroyed *before* the window gets destroyed to avoid memory leaks
SDL_DestroyRenderer(myRenderer);
@ -310,7 +311,7 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
mode.screenS.w, mode.screenS.h, flags);
if(myWindow == nullptr)
{
string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
const string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
Logger::error(msg);
return false;
}
@ -331,8 +332,12 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
ostringstream msg;
msg << "Display refresh rate changed to "
<< adaptedSdlMode.refresh_rate << " Hz";
Logger::info(msg.str());
<< adaptedSdlMode.refresh_rate << " Hz " << "(" << adaptedSdlMode.w << "x" << adaptedSdlMode.h << ")";
Logger::info(msg.view());
SDL_DisplayMode setSdlMode;
SDL_GetWindowDisplayMode(myWindow, &setSdlMode);
cerr << setSdlMode.refresh_rate << "Hz\n";
}
}
#endif
@ -358,8 +363,8 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
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));
float factor = std::min(
static_cast<float>(currentRefreshRate) / wantedRefreshRate, static_cast<float>(currentRefreshRate) / (wantedRefreshRate - 1));
// Calculate difference taking care of integer factors (e.g. 100/120)
float bestDiff = std::abs(factor - std::round(factor)) / factor;
bool adapt = false;
@ -370,7 +375,7 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
// Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
for(int m = 1; m <= 2; ++m)
{
SDL_DisplayMode closestSdlMode;
SDL_DisplayMode closestSdlMode{};
sdlMode.refresh_rate = wantedRefreshRate * m;
if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr)
@ -378,8 +383,9 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
Logger::error("ERROR: Closest display mode could not be retrieved");
return adapt;
}
factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate,
float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
factor = std::min(
static_cast<float>(sdlMode.refresh_rate) / sdlMode.refresh_rate,
static_cast<float>(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
const float diff = std::abs(factor - std::round(factor)) / factor;
if(diff < bestDiff)
{
@ -393,7 +399,7 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
// cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)";
//else
// cerr << "not required/possible";
//cerr << endl;
//cerr << '\n';
// Only change if the display supports a better refresh rate
return adapt;
@ -411,7 +417,7 @@ bool FBBackendSDL2::createRenderer()
bool recreate = myRenderer == nullptr;
uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
const string& video = myOSystem.settings().getString("video"); // Render hint
SDL_RendererInfo renderInfo;
SDL_RendererInfo renderInfo{};
if(myOSystem.settings().getBool("vsync")
&& !myOSystem.settings().getBool("turbo")) // V'synced blits option
@ -424,11 +430,11 @@ bool FBBackendSDL2::createRenderer()
if(recreate)
{
//cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl;
//cerr << "Create new renderer for buffer type #" << int(myBufferType) << '\n';
if(myRenderer)
SDL_DestroyRenderer(myRenderer);
if(video != "")
if(!video.empty())
SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
@ -438,8 +444,8 @@ bool FBBackendSDL2::createRenderer()
if(myRenderer == nullptr)
{
string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
Logger::error(msg);
Logger::error("ERROR: Unable to create SDL renderer: " +
string{SDL_GetError()});
return false;
}
}
@ -454,14 +460,14 @@ bool FBBackendSDL2::createRenderer()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL2::setTitle(const string& title)
void FBBackendSDL2::setTitle(string_view title)
{
ASSERT_MAIN_THREAD;
myScreenTitle = title;
if(myWindow)
SDL_SetWindowTitle(myWindow, title.c_str());
SDL_SetWindowTitle(myWindow, string{title}.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -470,18 +476,18 @@ string FBBackendSDL2::about() const
ASSERT_MAIN_THREAD;
ostringstream out;
out << "Video system: " << SDL_GetCurrentVideoDriver() << endl;
out << "Video system: " << SDL_GetCurrentVideoDriver() << '\n';
SDL_RendererInfo info;
if(SDL_GetRendererInfo(myRenderer, &info) >= 0)
{
out << " Renderer: " << info.name << endl;
out << " Renderer: " << info.name << '\n';
if(info.max_texture_width > 0 && info.max_texture_height > 0)
out << " Max texture: " << info.max_texture_width << "x"
<< info.max_texture_height << endl;
<< info.max_texture_height << '\n';
out << " Flags: "
<< ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, "
<< ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel"
<< endl;
<< '\n';
}
return out.str();
}
@ -567,7 +573,7 @@ unique_ptr<FBSurface> FBBackendSDL2::createSurface(
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
void FBBackendSDL2::readPixels(uInt8* buffer, size_t pitch,
const Common::Rect& rect) const
{
ASSERT_MAIN_THREAD;
@ -576,7 +582,7 @@ void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
r.x = rect.x(); r.y = rect.y();
r.w = rect.w(); r.h = rect.h();
SDL_RenderReadPixels(myRenderer, &r, 0, pixels, pitch);
SDL_RenderReadPixels(myRenderer, &r, 0, buffer, static_cast<int>(pitch));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -78,7 +78,7 @@ class FBBackendSDL2 : public FBBackend
@param title The title of the application / window
*/
void setTitle(const string& title) override;
void setTitle(string_view title) override;
/**
Shows or hides the cursor based on the given boolean value.
@ -98,9 +98,21 @@ class FBBackendSDL2 : public FBBackend
@param g The green component of the color
@param b The blue component of the color
*/
inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
{ SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
/**
This method is called to retrieve the R/G/B/A data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
@param a The alpha component of the color.
*/
FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override
{ SDL_GetRGBA(pixel, myPixelFormat, r, g, b, a); }
/**
This method is called to map a given R/G/B triple to the screen palette.
@ -108,9 +120,20 @@ class FBBackendSDL2 : public FBBackend
@param g The green component of the color.
@param b The blue component of the color.
*/
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
{ return SDL_MapRGB(myPixelFormat, r, g, b); }
/**
This method is called to map a given R/G/B/A triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
@param a The alpha component of the color.
*/
uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
{ return SDL_MapRGBA(myPixelFormat, r, g, b, a); }
/**
This method is called to get a copy of the specified ARGB data from the
viewable FrameBuffer area. Note that this isn't the same as any
@ -121,7 +144,7 @@ class FBBackendSDL2 : public FBBackend
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
void readPixels(uInt8* buffer, uInt32 pitch,
void readPixels(uInt8* buffer, size_t pitch,
const Common::Rect& rect) const override;
/**

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -38,7 +38,7 @@ namespace {
throw runtime_error("unreachable");
}
}
}
} // namespace
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
@ -48,6 +48,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
: myBackend{backend},
myInterpolationMode{inter}
{
//cerr << width << " x " << height << '\n';
createSurface(width, height, staticData);
}
@ -233,6 +234,7 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
mySurface = SDL_CreateRGBSurface(0, width, height,
pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask);
//SDL_SetSurfaceBlendMode(mySurface, SDL_BLENDMODE_ADD); // default: SDL_BLENDMODE_BLEND
// We start out with the src and dst rectangles containing the same
// dimensions, indicating no scaling or re-positioning
@ -249,9 +251,10 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
myIsStatic = data != nullptr;
if(myIsStatic)
SDL_memcpy(mySurface->pixels, data, mySurface->w * mySurface->h * 4);
SDL_memcpy(mySurface->pixels, data,
static_cast<size_t>(mySurface->w) * mySurface->h * 4);
reload();
reload(); // NOLINT
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -278,8 +281,12 @@ void FBSurfaceSDL2::applyAttributes()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation)
{
if (interpolation == ScalingInterpolation::sharp
&& mySrcGUIR.h() >= myDstGUIR.h())
if (interpolation == ScalingInterpolation::sharp &&
(
static_cast<int>(mySrcGUIR.h()) >= myBackend.scaleY(myDstGUIR.h()) ||
static_cast<int>(mySrcGUIR.w()) >= myBackend.scaleX(myDstGUIR.w())
)
)
interpolation = ScalingInterpolation::blur;
if (interpolation == myInterpolationMode) return;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -69,8 +69,8 @@ class FBSurfaceSDL2 : public FBSurface
void applyAttributes() override;
private:
inline bool setSrcPosInternal(uInt32 x, uInt32 y) {
if(x != static_cast<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
bool setSrcPosInternal(uInt32 x, uInt32 y) {
if(std::cmp_not_equal(x, mySrcR.x) || std::cmp_not_equal(y, mySrcR.y))
{
mySrcR.x = x; mySrcR.y = y;
mySrcGUIR.moveTo(x, y);
@ -78,8 +78,8 @@ class FBSurfaceSDL2 : public FBSurface
}
return false;
}
inline bool setSrcSizeInternal(uInt32 w, uInt32 h) {
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(mySrcR.h))
bool setSrcSizeInternal(uInt32 w, uInt32 h) {
if(std::cmp_not_equal(w, mySrcR.w) || std::cmp_not_equal(h, mySrcR.h))
{
mySrcR.w = w; mySrcR.h = h;
mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h);
@ -87,8 +87,8 @@ class FBSurfaceSDL2 : public FBSurface
}
return false;
}
inline bool setDstPosInternal(uInt32 x, uInt32 y) {
if(x != static_cast<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
bool setDstPosInternal(uInt32 x, uInt32 y) {
if(std::cmp_not_equal(x, myDstR.x) || std::cmp_not_equal(y, myDstR.y))
{
myDstR.x = x; myDstR.y = y;
myDstGUIR.moveTo(x, y);
@ -96,8 +96,8 @@ class FBSurfaceSDL2 : public FBSurface
}
return false;
}
inline bool setDstSizeInternal(uInt32 w, uInt32 h) {
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(myDstR.h))
bool setDstSizeInternal(uInt32 w, uInt32 h) {
if(std::cmp_not_equal(w, myDstR.w) || std::cmp_not_equal(h, myDstR.h))
{
myDstR.w = w; myDstR.h = h;
myDstGUIR.setWidth(w); myDstGUIR.setHeight(h);

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -38,41 +38,44 @@ class AbstractFSNode;
@author Stephen Anthony
*/
class FilesystemNodeFactory
class FSNodeFactory
{
public:
enum class Type { SYSTEM, ZIP };
enum class Type: uInt8 { SYSTEM, ZIP };
public:
static unique_ptr<AbstractFSNode> create(const string& path, Type type)
static unique_ptr<AbstractFSNode> create(string_view path, Type type)
{
switch(type)
{
case Type::SYSTEM:
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
return make_unique<FilesystemNodePOSIX>(path);
return make_unique<FSNodePOSIX>(path);
#elif defined(BSPF_WINDOWS)
return make_unique<FilesystemNodeWINDOWS>(path);
return make_unique<FSNodeWINDOWS>(path);
#elif defined(__LIB_RETRO__)
return make_unique<FilesystemNodeLIBRETRO>(path);
return make_unique<FSNodeLIBRETRO>(path);
#endif
break;
case Type::ZIP:
#if defined(ZIP_SUPPORT)
return make_unique<FilesystemNodeZIP>(path);
return make_unique<FSNodeZIP>(path);
#endif
break;
default:
break;
}
return nullptr;
return nullptr; // satisfy compiler
}
private:
// Following constructors and assignment operators not supported
FilesystemNodeFactory() = delete;
FilesystemNodeFactory(const FilesystemNodeFactory&) = delete;
FilesystemNodeFactory(FilesystemNodeFactory&&) = delete;
FilesystemNodeFactory& operator=(const FilesystemNodeFactory&) = delete;
FilesystemNodeFactory& operator=(FilesystemNodeFactory&&) = delete;
FSNodeFactory() = delete;
~FSNodeFactory() = delete;
FSNodeFactory(const FSNodeFactory&) = delete;
FSNodeFactory(FSNodeFactory&&) = delete;
FSNodeFactory& operator=(const FSNodeFactory&) = delete;
FSNodeFactory& operator=(FSNodeFactory&&) = delete;
};
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -21,12 +21,11 @@
#include "bspf.hxx"
#include "Bankswitch.hxx"
#include "OSystem.hxx"
#include "FSNodeFactory.hxx"
#include "FSNodeZIP.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
FSNodeZIP::FSNodeZIP(string_view p)
{
// Extract ZIP file and virtual file (if specified)
const size_t pos = BSPF::findIgnoreCase(p, ".zip");
@ -36,18 +35,18 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
_zipFile = p.substr(0, pos+4);
// Expand '~' to the users 'home' directory
if (_zipFile[0] == '~')
if(_zipFile[0] == '~')
{
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
const char* home = std::getenv("HOME");
if (home != nullptr)
const char* const home = std::getenv("HOME"); // NOLINT (not thread safe)
if(home != nullptr)
_zipFile.replace(0, 1, home);
#elif defined(BSPF_WINDOWS)
_zipFile.replace(0, 1, myHomeFinder.getHomePath());
_zipFile.replace(0, 1, HomeFinder::getHomePath());
#endif
}
// cerr << " => p: " << p << endl;
// cerr << " => p: " << p << '\n';
// Open file at least once to initialize the virtual file count
try
@ -100,30 +99,28 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
// has direct access to the actual filesystem (aka, a 'System' node)
// Behind the scenes, this node is actually a platform-specific object
// for whatever system we are running on
_realNode = FilesystemNodeFactory::create(_zipFile,
FilesystemNodeFactory::Type::SYSTEM);
_realNode = FSNodeFactory::create(_zipFile,
FSNodeFactory::Type::SYSTEM);
setFlags(_zipFile, _virtualPath, _realNode);
// cerr << "==============================================================\n";
// cerr << _name << ", file: " << _isFile << ", dir: " << _isDirectory << endl << endl;
// cerr << _name << ", file: " << _isFile << ", dir: " << _isDirectory << "\n\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilesystemNodeZIP::FilesystemNodeZIP(
const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode, size_t size, bool isdir)
FSNodeZIP::FSNodeZIP(const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode, size_t size, bool isdir)
: _size{size},
_isDirectory{isdir},
_isFile{!isdir}
{
// cerr << "=> c'tor 2: " << zipfile << ", " << virtualpath << ", " << isdir << endl;
// cerr << "=> c'tor 2: " << zipfile << ", " << virtualpath << ", " << isdir << '\n';
setFlags(zipfile, virtualpath, realnode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FilesystemNodeZIP::setFlags(const string& zipfile,
const string& virtualpath,
const AbstractFSNodePtr& realnode)
void FSNodeZIP::setFlags(const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode)
{
_zipFile = zipfile;
_virtualPath = virtualpath;
@ -133,7 +130,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
_shortPath = _realNode->getShortPath();
// Is a file component present?
if(_virtualPath.size() != 0)
if(!_virtualPath.empty())
{
_path += ("/" + _virtualPath);
_shortPath += ("/" + _virtualPath);
@ -147,7 +144,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FilesystemNodeZIP::exists() const
bool FSNodeZIP::exists() const
{
if(_realNode && _realNode->exists())
{
@ -165,6 +162,7 @@ bool FilesystemNodeZIP::exists() const
catch(const runtime_error&)
{
// TODO: Actually present the error passed in back to the user
cerr << "ERROR: FSNodeZIP::exists()\n";
}
}
@ -172,7 +170,7 @@ bool FilesystemNodeZIP::exists() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
bool FSNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
{
// Files within ZIP archives don't contain children
if(!isDirectory() || _error != zip_error::NONE)
@ -180,7 +178,6 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
std::set<string> dirs;
myZipHandler->open(_zipFile);
// cerr << "CHILDREN: --------------------------------\n";
while(myZipHandler->hasNext())
{
// Only consider entries that start with '_virtualPath'
@ -192,39 +189,37 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
{
// First strip off the leading directory
const string& curr = name.substr(
_virtualPath == "" ? 0 : _virtualPath.size()+1);
// cerr << " curr: " << curr << endl;
_virtualPath.empty() ? 0 : _virtualPath.size()+1);
// Only add sub-directory entries once
const auto pos = curr.find_first_of("/\\");
if(pos != string::npos)
dirs.emplace(curr.substr(0, pos));
else
myList.emplace_back(new FilesystemNodeZIP(_zipFile, name, _realNode, size, false));
myList.emplace_back(new FSNodeZIP(_zipFile, name, _realNode, size, false));
}
}
for(const auto& dir: dirs)
{
// Prepend previous path
const string& vpath = _virtualPath != "" ? _virtualPath + "/" + dir : dir;
myList.emplace_back(new FilesystemNodeZIP(_zipFile, vpath, _realNode, 0, true));
const string& vpath = !_virtualPath.empty() ? _virtualPath + "/" + dir : dir;
myList.emplace_back(new FSNodeZIP(_zipFile, vpath, _realNode, 0, true));
}
// cerr << "list: \n";
// for(auto& s: myList)
// cerr << s->getPath() << " : isdir: " << s->isDirectory() << endl;
// cerr << "------------------------------------------\n";
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FilesystemNodeZIP::read(ByteBuffer& image, size_t) const
size_t FSNodeZIP::read(ByteBuffer& buffer, size_t) const
{
switch(_error)
{
case zip_error::NONE: break;
case zip_error::NOT_A_FILE: throw runtime_error("ZIP file contains errors/not found");
case zip_error::NOT_READABLE: throw runtime_error("ZIP file not readable");
case zip_error::NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs");
using enum zip_error;
case NONE: break;
case NOT_A_FILE: throw runtime_error("ZIP file contains errors/not found");
case NOT_READABLE: throw runtime_error("ZIP file not readable");
case NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs");
default: throw runtime_error("FSNodeZIP::read default case hit");
}
myZipHandler->open(_zipFile);
@ -236,49 +231,58 @@ size_t FilesystemNodeZIP::read(ByteBuffer& image, size_t) const
found = name == _virtualPath;
}
return found ? myZipHandler->decompress(image) : 0;
return found ? myZipHandler->decompress(buffer) : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FilesystemNodeZIP::read(stringstream& image) const
size_t FSNodeZIP::read(stringstream& buffer) const
{
// For now, we just read into a buffer and store in the stream
// TODO: maybe there's a more efficient way to do this?
ByteBuffer buffer;
const size_t size = read(buffer, 0);
ByteBuffer read_buf;
const size_t size = read(read_buf, 0);
if(size > 0)
image.write(reinterpret_cast<char*>(buffer.get()), size);
buffer.write(reinterpret_cast<char*>(read_buf.get()), size);
return size;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FilesystemNodeZIP::write(const ByteBuffer& buffer, size_t size) const
size_t FSNodeZIP::write(const ByteBuffer& buffer, size_t) const
{
// TODO: Not yet implemented
throw runtime_error("ZIP file not writable");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t FilesystemNodeZIP::write(const stringstream& buffer) const
size_t FSNodeZIP::write(const stringstream& buffer) const
{
// TODO: Not yet implemented
throw runtime_error("ZIP file not writable");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AbstractFSNodePtr FilesystemNodeZIP::getParent() const
AbstractFSNodePtr FSNodeZIP::getParent() const
{
if(_virtualPath == "")
if(_virtualPath.empty())
return _realNode ? _realNode->getParent() : nullptr;
const char* start = _path.c_str();
const char* end = lastPathComponent(_path);
// TODO: For some reason, getting the stem for normal paths and zip paths
// behaves differently. For now, we'll use the old method here.
auto STEM_FOR_ZIP = [](string_view s) {
const char* const start = s.data();
const char* cur = start + s.size() - 2;
return make_unique<FilesystemNodeZIP>(string(start, end - start - 1));
while (cur >= start && !(*cur == '/' || *cur == '\\'))
--cur;
return s.substr(0, (cur + 1) - start - 1);
};
return make_unique<FSNodeZIP>(STEM_FOR_ZIP(_path));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<ZipHandler> FilesystemNodeZIP::myZipHandler = make_unique<ZipHandler>();
unique_ptr<ZipHandler> FSNodeZIP::myZipHandler = make_unique<ZipHandler>();
#endif // ZIP_SUPPORT

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -32,19 +32,19 @@
*
* Parts of this class are documented in the base interface class, AbstractFSNode.
*/
class FilesystemNodeZIP : public AbstractFSNode
class FSNodeZIP : public AbstractFSNode
{
public:
/**
* Creates a FilesystemNodeZIP for a given path.
* Creates a FSNodeZIP for a given path.
*
* @param path String with the path the new node should point to.
*/
explicit FilesystemNodeZIP(const string& path);
explicit FSNodeZIP(string_view path);
bool exists() const override;
const string& getName() const override { return _name; }
void setName(const string& name) override { _name = name; }
const string& getName() const override { return _name; }
void setName(string_view name) override { _name = name; }
const string& getPath() const override { return _path; }
string getShortPath() const override { return _shortPath; }
bool hasParent() const override { return true; }
@ -56,39 +56,39 @@ class FilesystemNodeZIP : public AbstractFSNode
//////////////////////////////////////////////////////////
// For now, ZIP files cannot be modified in any way
bool makeDir() override { return false; }
bool rename(const string& newfile) override { return false; }
bool rename(string_view) override { return false; }
//////////////////////////////////////////////////////////
size_t getSize() const override { return _size; }
bool getChildren(AbstractFSList& list, ListMode mode) const override;
AbstractFSNodePtr getParent() const override;
size_t read(ByteBuffer& buffer, size_t size) const override;
size_t read(ByteBuffer& buffer, size_t) const override;
size_t read(stringstream& buffer) const override;
size_t write(const ByteBuffer& buffer, size_t size) const override;
size_t write(const ByteBuffer& buffer, size_t) const override;
size_t write(const stringstream& buffer) const override;
private:
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
FSNodeZIP(const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode, size_t size, bool isdir);
void setFlags(const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode);
friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node)
friend ostream& operator<<(ostream& os, const FSNodeZIP& node)
{
os << "_zipFile: " << node._zipFile << endl
<< "_virtualPath: " << node._virtualPath << endl
<< "_name: " << node._name << endl
<< "_path: " << node._path << endl
<< "_size: " << node._size << endl
<< "_shortPath: " << node._shortPath << endl;
os << "_zipFile: " << node._zipFile << '\n'
<< "_virtualPath: " << node._virtualPath << '\n'
<< "_name: " << node._name << '\n'
<< "_path: " << node._path << '\n'
<< "_size: " << node._size << '\n'
<< "_shortPath: " << node._shortPath << '\n';
return os;
}
private:
/* Error types */
enum class zip_error
enum class zip_error: uInt8
{
NONE,
NOT_A_FILE,

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -46,32 +46,27 @@ void FpsMeter::render(uInt32 frameCount)
}
const size_t queueSize = myQueue.capacity();
entry first, last;
entry e_first, e_last;
last.frames = frameCount;
last.timestamp = high_resolution_clock::now();
e_last.frames = frameCount;
e_last.timestamp = high_resolution_clock::now();
if (myQueue.size() < queueSize) {
myQueue.push_back(last);
myQueue.push_back(e_last);
myFrameCount += frameCount;
first = myQueue.at(myQueueOffset);
e_first = myQueue.at(myQueueOffset);
} else {
myFrameCount = myFrameCount - myQueue.at(myQueueOffset).frames + frameCount;
myQueue.at(myQueueOffset) = last;
myQueue.at(myQueueOffset) = e_last;
myQueueOffset = (myQueueOffset + 1) % queueSize;
first = myQueue.at(myQueueOffset);
e_first = myQueue.at(myQueueOffset);
}
const float myTimeInterval =
duration_cast<duration<float>>(last.timestamp - first.timestamp).count();
duration_cast<duration<float>>(e_last.timestamp - e_first.timestamp).count();
if (myTimeInterval > 0) myFps = (myFrameCount - first.frames) / myTimeInterval;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float FpsMeter::fps() const
{
return myFps;
if (myTimeInterval > 0)
myFps = (myFrameCount - e_first.frames) / myTimeInterval;
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -27,12 +27,13 @@ class FpsMeter
public:
explicit FpsMeter(uInt32 queueSize);
~FpsMeter() = default;
void reset(uInt32 garbageFrameLimit = 0);
void render(uInt32 frameCount);
float fps() const;
float fps() const { return myFps; }
private:

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -65,9 +65,10 @@ HighScoresManager::HighScoresManager(OSystem& osystem)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::setRepository(shared_ptr<CompositeKeyValueRepositoryAtomic> repo)
void HighScoresManager::setRepository(
shared_ptr<CompositeKeyValueRepositoryAtomic> repo)
{
myHighscoreRepository = repo;
myHighscoreRepository = std::move(repo);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -76,7 +77,7 @@ Int16 HighScoresManager::peek(uInt16 addr) const
if (myOSystem.hasConsole())
{
if(addr < 0x100U || myOSystem.console().cartridge().internalRamSize() == 0)
return myOSystem.console().system().peek(addr);
return myOSystem.console().system().peekOob(addr);
else
return myOSystem.console().cartridge().internalRamGetValue(addr);
}
@ -84,7 +85,7 @@ Int16 HighScoresManager::peek(uInt16 addr) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const json HighScoresManager::properties(const Properties& props) const
json HighScoresManager::properties(const Properties& props)
{
const string& property = props.get(PropType::Cart_Highscore);
@ -94,7 +95,6 @@ const json HighScoresManager::properties(const Properties& props) const
return json::parse(property);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json HighScoresManager::properties(json& jprops) const
{
@ -113,7 +113,6 @@ json HighScoresManager::properties(json& jprops) const
return jprops = properties(props);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::enabled() const
{
@ -123,17 +122,16 @@ bool HighScoresManager::enabled() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numVariations(const json& jprops) const
uInt32 HighScoresManager::numVariations(const json& jprops)
{
return min(getPropInt(jprops, VARIATIONS_COUNT, DEFAULT_VARIATION), MAX_VARIATIONS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
ScoresProps& info) const
{
json jprops = properties(props);
const json jprops = properties(props);
numVariationsR = numVariations(jprops);
@ -158,7 +156,7 @@ bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::set(Properties& props, uInt32 numVariations,
const ScoresProps& info) const
const ScoresProps& info)
{
json jprops = json::object();
@ -206,85 +204,79 @@ void HighScoresManager::set(Properties& props, uInt32 numVariations,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numDigits(const json& jprops) const
uInt32 HighScoresManager::numDigits(const json& jprops)
{
return min(getPropInt(jprops, SCORE_DIGITS, DEFAULT_DIGITS), MAX_SCORE_DIGITS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::trailingZeroes(const json& jprops) const
uInt32 HighScoresManager::trailingZeroes(const json& jprops)
{
return min(getPropInt(jprops, SCORE_TRAILING_ZEROES, DEFAULT_TRAILING), MAX_TRAILING);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::scoreBCD(const json& jprops) const
bool HighScoresManager::scoreBCD(const json& jprops)
{
return getPropBool(jprops, SCORE_BCD, DEFAULT_SCORE_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::scoreInvert(const json& jprops) const
bool HighScoresManager::scoreInvert(const json& jprops)
{
return getPropBool(jprops, SCORE_INVERTED, DEFAULT_SCORE_REVERSED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::varBCD(const json& jprops) const
bool HighScoresManager::varBCD(const json& jprops)
{
return getPropBool(jprops, VARIATIONS_BCD, DEFAULT_VARS_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::varZeroBased(const json& jprops) const
bool HighScoresManager::varZeroBased(const json& jprops)
{
return getPropBool(jprops, VARIATIONS_ZERO_BASED, DEFAULT_VARS_ZERO_BASED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::specialLabel(const json& jprops) const
string HighScoresManager::specialLabel(const json& jprops)
{
return getPropStr(jprops, SPECIAL_LABEL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::specialBCD(const json& jprops) const
bool HighScoresManager::specialBCD(const json& jprops)
{
return getPropBool(jprops, SPECIAL_BCD, DEFAULT_SPECIAL_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::specialZeroBased(const json& jprops) const
bool HighScoresManager::specialZeroBased(const json& jprops)
{
return getPropBool(jprops, SPECIAL_ZERO_BASED, DEFAULT_SPECIAL_ZERO_BASED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::notes(const json& jprops) const
string HighScoresManager::notes(const json& jprops)
{
return getPropStr(jprops, NOTES);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::varAddress(const json& jprops) const
uInt16 HighScoresManager::varAddress(const json& jprops)
{
return getPropAddr(jprops, VARIATIONS_ADDRESS, DEFAULT_ADDRESS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::specialAddress(const json& jprops) const
uInt16 HighScoresManager::specialAddress(const json& jprops)
{
return getPropAddr(jprops, SPECIAL_ADDRESS, DEFAULT_ADDRESS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numAddrBytes(Int32 digits, Int32 trailing) const
{
return (digits - trailing + 1) / 2;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numAddrBytes(const json& jprops) const
uInt32 HighScoresManager::numAddrBytes(const json& jprops)
{
return numAddrBytes(numDigits(jprops), trailingZeroes(jprops));
}
@ -298,7 +290,7 @@ Int32 HighScoresManager::numVariations() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::specialLabel() const
string HighScoresManager::specialLabel() const
{
json jprops;
@ -321,7 +313,7 @@ Int32 HighScoresManager::variation(uInt16 addr, bool varBCD, bool zeroBased,
Int32 HighScoresManager::variation() const
{
json jprops;
uInt16 addr = varAddress(properties(jprops));
const uInt16 addr = varAddress(properties(jprops));
if(addr == DEFAULT_ADDRESS) {
if(numVariations() == 1)
@ -369,7 +361,7 @@ Int32 HighScoresManager::score(uInt32 numAddrBytes, uInt32 trailingZeroes,
Int32 HighScoresManager::score() const
{
json jprops;
uInt32 numBytes = numAddrBytes(properties(jprops));
const uInt32 numBytes = numAddrBytes(properties(jprops));
const ScoreAddresses scoreAddr = getPropScoreAddr(jprops);
if(static_cast<uInt32>(scoreAddr.size()) < numBytes)
@ -378,7 +370,7 @@ Int32 HighScoresManager::score() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
string HighScoresManager::formattedScore(Int32 score, Int32 width) const
{
if(score <= 0)
return "";
@ -389,8 +381,7 @@ const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
if(scoreBCD(jprops))
{
if(width > digits)
digits = width;
digits = std::max(width, digits);
buf << std::setw(digits) << std::setfill(' ') << score;
}
else {
@ -402,6 +393,7 @@ const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string HighScoresManager::md5Props() const
{
json jprops;
@ -421,9 +413,10 @@ string HighScoresManager::md5Props() const
buf << specialAddress(jprops) << specialBCD(jprops) << specialZeroBased(jprops);
return MD5::hash(buf.str());
return MD5::hash(buf.view());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::scoreInvert() const
{
json jprops;
@ -438,7 +431,7 @@ Int32 HighScoresManager::special() const
return NO_VALUE;
json jprops;
uInt16 addr = specialAddress(properties(jprops));
const uInt16 addr = specialAddress(properties(jprops));
if (addr == DEFAULT_ADDRESS)
return NO_VALUE;
@ -454,7 +447,7 @@ Int32 HighScoresManager::special() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::notes() const
string HighScoresManager::notes() const
{
json jprops;
@ -462,13 +455,14 @@ const string HighScoresManager::notes() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD,
bool zeroBased)
{
//maxVal += zeroBased ? 0 : 1;
maxVal -= zeroBased ? 1 : 0;
const Int32 bits = isBCD
? ceil(log(maxVal) / log(10) * 4)
: ceil(log(maxVal) / log(2));
? ceil(log(maxVal) / BSPF::ln10 * 4)
: ceil(log(maxVal) / BSPF::ln2);
// limit to maxVal's bits
val %= 1 << bits;
@ -485,30 +479,29 @@ Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zero
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::getPropBool(const json& jprops, const string& key,
bool defVal) const
bool HighScoresManager::getPropBool(const json& jprops, string_view key,
bool defVal)
{
return jprops.contains(key) ? jprops.at(key).get<bool>() : defVal;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::getPropInt(const json& jprops, const string& key,
uInt32 defVal) const
uInt32 HighScoresManager::getPropInt(const json& jprops, string_view key,
uInt32 defVal)
{
return jprops.contains(key) ? jprops.at(key).get<uInt32>() : defVal;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::getPropStr(const json& jprops, const string& key,
const string& defVal) const
string HighScoresManager::getPropStr(const json& jprops, string_view key,
string_view defVal)
{
return jprops.contains(key) ? jprops.at(key).get<string>() : defVal;
return jprops.contains(key) ? jprops.at(key).get<string>() : string{defVal};
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
uInt16 defVal) const
uInt16 HighScoresManager::getPropAddr(const json& jprops, string_view key,
uInt16 defVal)
{
const string str = getPropStr(jprops, key);
@ -516,7 +509,7 @@ uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops) const
HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops)
{
ScoreAddresses scoreAddr{};
@ -543,18 +536,16 @@ const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::fromHexStr(const string& addr) const
uInt16 HighScoresManager::fromHexStr(string_view addr)
{
string naked = addr;
if(const auto pos = addr.find("0x") != std::string::npos)
addr = addr.substr(pos + 1);
if(const int pos = naked.find("0x") != std::string::npos)
naked = naked.substr(pos + 1);
return stringToIntBase16(naked);
return static_cast<uInt16>(BSPF::stoi<16>(addr));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::fromBCD(uInt8 bcd) const
Int32 HighScoresManager::fromBCD(uInt8 bcd)
{
// verify if score is legit
if ((bcd & 0xF0) >= 0xA0 || (bcd & 0xF) >= 0xA)
@ -578,7 +569,7 @@ string HighScoresManager::hash(const ScoresData& data) const
<< data.scores[r].date;
}
return MD5::hash(buf.str());
return MD5::hash(buf.view());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -665,7 +656,7 @@ void HighScoresManager::loadHighScores(ScoresData& data)
clearHighScores(data);
buf << "Error: Invalid high scores data for variation " << data.variation << ".";
}
myOSystem.frameBuffer().showTextMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.view());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -701,12 +692,12 @@ bool HighScoresManager::load(const json& hsData, ScoresData& data)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::clearHighScores(ScoresData& data)
{
for(uInt32 r = 0; r < NUM_RANKS; ++r)
for(auto& s: data.scores)
{
data.scores[r].score = 0;
data.scores[r].special = 0;
data.scores[r].name = "";
data.scores[r].date = "";
s.score = 0;
s.special = 0;
s.name = "";
s.date = "";
}
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -65,7 +65,7 @@ namespace HSM {
bool specialZeroBased{false};
string notes;
// Addresses
ScoreAddresses scoreAddr;
ScoreAddresses scoreAddr{};
uInt16 varsAddr{0};
uInt16 specialAddr{0};
};
@ -112,8 +112,8 @@ class HighScoresManager
/**
Set the highscore data of game's properties
*/
void set(Properties& props, uInt32 numVariations,
const HSM::ScoresProps& info) const;
static void set(Properties& props, uInt32 numVariations,
const HSM::ScoresProps& info);
/**
Calculate the score from given parameters
@ -125,24 +125,26 @@ class HighScoresManager
// Convert the given value, using only the maximum bits required by maxVal
// and adjusted for BCD and zero based data
Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const;
static Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased);
/**
Calculate the number of bytes for one player's score from given parameters
@return The number of score address bytes
*/
uInt32 numAddrBytes(Int32 digits, Int32 trailing) const;
static constexpr uInt32 numAddrBytes(Int32 digits, Int32 trailing) {
return (digits - trailing + 1) / 2;
}
// Retrieve current values (using game's properties)
Int32 numVariations() const;
const string specialLabel() const;
string specialLabel() const;
Int32 variation() const;
Int32 score() const;
const string formattedScore(Int32 score, Int32 width = -1) const;
string formattedScore(Int32 score, Int32 width = -1) const;
bool scoreInvert() const;
Int32 special() const;
const string notes() const;
string notes() const;
// Get md5 property definition checksum
string md5Props() const;
@ -150,8 +152,8 @@ class HighScoresManager
// Peek into memory
Int16 peek(uInt16 addr) const;
void loadHighScores(HSM::ScoresData& scores);
void saveHighScores(HSM::ScoresData& scores) const;
void loadHighScores(HSM::ScoresData& data);
void saveHighScores(HSM::ScoresData& data) const;
private:
static const string VARIATIONS_COUNT;
@ -198,53 +200,53 @@ class HighScoresManager
Int32 variation(uInt16 addr, bool varBCD, bool zeroBased, uInt32 numVariations) const;
// Get individual highscore info from properties
uInt32 numVariations(const json& jprops) const;
uInt16 varAddress(const json& jprops) const;
uInt16 specialAddress(const json& jprops) const;
uInt32 numDigits(const json& jprops) const;
uInt32 trailingZeroes(const json& jprops) const;
bool scoreBCD(const json& jprops) const;
bool scoreInvert(const json& jprops) const;
bool varBCD(const json& jprops) const;
bool varZeroBased(const json& jprops) const;
const string specialLabel(const json& jprops) const;
bool specialBCD(const json& jprops) const;
bool specialZeroBased(const json& jprops) const;
const string notes(const json& jprops) const;
static uInt32 numVariations(const json& jprops);
static uInt16 varAddress(const json& jprops);
static uInt16 specialAddress(const json& jprops);
static uInt32 numDigits(const json& jprops);
static uInt32 trailingZeroes(const json& jprops);
static bool scoreBCD(const json& jprops);
static bool scoreInvert(const json& jprops);
static bool varBCD(const json& jprops);
static bool varZeroBased(const json& jprops);
static string specialLabel(const json& jprops);
static bool specialBCD(const json& jprops);
static bool specialZeroBased(const json& jprops);
static string notes(const json& jprops);
// Calculate the number of bytes for one player's score from property parameters
uInt32 numAddrBytes(const json& jprops) const;
static uInt32 numAddrBytes(const json& jprops);
// Get properties
const json properties(const Properties& props) const;
static json properties(const Properties& props);
json properties(json& jprops) const;
// Get value from highscore properties for given key
bool getPropBool(const json& jprops, const string& key,
bool defVal = false) const;
uInt32 getPropInt(const json& jprops, const string& key,
uInt32 defVal = 0) const;
const string getPropStr(const json& jprops, const string& key,
const string& defVal = "") const;
uInt16 getPropAddr(const json& jprops, const string& key,
uInt16 defVal = 0) const;
const HSM::ScoreAddresses getPropScoreAddr(const json& jprops) const;
static bool getPropBool(const json& jprops, string_view key,
bool defVal = false);
static uInt32 getPropInt(const json& jprops, string_view key,
uInt32 defVal = 0);
static string getPropStr(const json& jprops, string_view key,
string_view defVal = "");
static uInt16 getPropAddr(const json& jprops, string_view key,
uInt16 defVal = 0);
static HSM::ScoreAddresses getPropScoreAddr(const json& jprops);
uInt16 fromHexStr(const string& addr) const;
Int32 fromBCD(uInt8 bcd) const;
static uInt16 fromHexStr(string_view addr);
static Int32 fromBCD(uInt8 bcd);
string hash(const HSM::ScoresData& data) const;
/**
Loads the current high scores for this game and variation from the given JSON object.
@param hsData The JSON to parse
@param scores The loaded high score data
@param data The loaded high score data
@return The result of the load. True on success, false on failure.
*/
bool load(const json& hsData, HSM::ScoresData& scores);
static bool load(const json& hsData, HSM::ScoresData& data);
void clearHighScores(HSM::ScoresData& data);
static void clearHighScores(HSM::ScoresData& data);
private:
// Reference to the osystem object
@ -261,4 +263,5 @@ class HighScoresManager
HighScoresManager& operator=(const HighScoresManager&) = delete;
HighScoresManager& operator=(HighScoresManager&&) = delete;
};
#endif

121
src/common/JPGLibrary.cxx Normal file
View File

@ -0,0 +1,121 @@
//============================================================================
//
// 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-2025 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.
//============================================================================
#ifdef IMAGE_SUPPORT
#include "OSystem.hxx"
#include "FrameBuffer.hxx"
#include "FBSurface.hxx"
#include "nanojpeg_lib.hxx"
#include "tinyexif_lib.hxx"
#include "JPGLibrary.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
JPGLibrary::JPGLibrary(OSystem& osystem)
: myOSystem{osystem}
{
njInit();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JPGLibrary::loadImage(const string& filename, FBSurface& surface,
VariantList& metaData)
{
std::ifstream in(filename, std::ios_base::binary | std::ios::ate);
if(!in.is_open())
throw runtime_error("No image found");
const size_t size = in.tellg();
in.clear();
in.seekg(0);
// Create space for the entire file
if(size > myFileBuffer.capacity())
myFileBuffer.reserve(size * 1.5);
if(!in.read(myFileBuffer.data(), size))
throw runtime_error("JPG image data reading failed");
if(njDecode(myFileBuffer.data(), static_cast<int>(size)))
throw runtime_error("Error decoding the JPG image");
// Read the entire image in one go
myReadInfo.buffer = njGetImage();
myReadInfo.width = njGetWidth();
myReadInfo.height = njGetHeight();
myReadInfo.pitch = myReadInfo.width * 3;
// Read the meta data we got
readMetaData(filename, metaData);
// Load image into the surface, setting the correct dimensions
loadImagetoSurface(surface);
// Cleanup
njDone();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JPGLibrary::loadImagetoSurface(FBSurface& surface)
{
// First determine if we need to resize the surface
const uInt32 iw = myReadInfo.width, ih = myReadInfo.height;
if(iw > surface.width() || ih > surface.height())
surface.resize(iw, ih);
// The source dimensions are set here; the destination dimensions are
// set by whoever owns the surface
surface.setSrcPos(0, 0);
surface.setSrcSize(iw, ih);
// Convert RGB triples into pixels and store in the surface
uInt32 *s_buf{nullptr}, s_pitch{0};
surface.basePtr(s_buf, s_pitch);
const uInt8* i_buf = myReadInfo.buffer;
const uInt32 i_pitch = myReadInfo.pitch;
const FrameBuffer& fb = myOSystem.frameBuffer();
for(uInt32 irow = 0; irow < ih; ++irow, i_buf += i_pitch, s_buf += s_pitch)
{
const uInt8* i_ptr = i_buf;
uInt32* s_ptr = s_buf;
for(uInt32 icol = 0; icol < myReadInfo.width; ++icol, i_ptr += 3)
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr + 1), *(i_ptr + 2));
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JPGLibrary::readMetaData(const string& filename, VariantList& metaData)
{
metaData.clear();
// open a stream to read just the necessary parts of the image file
std::ifstream in(filename, std::ifstream::binary);
// parse image EXIF metadata
const TinyEXIF::EXIFInfo imageEXIF(in);
if(imageEXIF.Fields)
{
// For now we only read the image description
if(!imageEXIF.ImageDescription.empty())
VarList::push_back(metaData, "ImageDescription", imageEXIF.ImageDescription);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::vector<char> JPGLibrary::myFileBuffer;
#endif // IMAGE_SUPPORT

96
src/common/JPGLibrary.hxx Normal file
View File

@ -0,0 +1,96 @@
//============================================================================
//
// 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-2025 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.
//============================================================================
#ifdef IMAGE_SUPPORT
#ifndef JPG_LIBRARY_HXX
#define JPG_LIBRARY_HXX
class OSystem;
class FBSurface;
#include "Variant.hxx"
#include "bspf.hxx"
/**
This class implements a thin wrapper around the nanojpeg library, and
abstracts all the irrelevant details other loading an actual image.
@author Thomas Jentzsch
*/
class JPGLibrary
{
public:
explicit JPGLibrary(OSystem& osystem);
~JPGLibrary() = default;
/**
Read a JPG image from the specified file into a FBSurface structure,
scaling the image to the surface bounds.
@param filename The filename to load the JPG image
@param surface The FBSurface into which to place the JPG data
@param metaData The meta data of the JPG image
@post On success, the FBSurface containing image data, otherwise a
runtime_error is thrown containing a more detailed
error message.
*/
void loadImage(const string& filename, FBSurface& surface,
VariantList& metaData);
private:
// Global OSystem object
OSystem& myOSystem;
// The following data remains between invocations of allocateStorage,
// and is only changed when absolutely necessary.
struct ReadInfoType {
unsigned char* buffer{nullptr};
uInt32 width{0}, height{0}, pitch{0};
};
ReadInfoType myReadInfo;
static std::vector<char> myFileBuffer;
/**
Load the JPG data from 'ReadInfo' into the FBSurface. The surface
is resized as necessary to accommodate the data.
@param surface The FBSurface into which to place the JPG data
*/
void loadImagetoSurface(FBSurface& surface);
/**
Read EXIF meta data chunks from the image.
@param filename The filename to load the JPG image
@param metaData The meta data of the JPG image
*/
static void readMetaData(const string& filename, VariantList& metaData);
private:
// Following constructors and assignment operators not supported
JPGLibrary() = delete;
JPGLibrary(const JPGLibrary&) = delete;
JPGLibrary(JPGLibrary&&) = delete;
JPGLibrary& operator=(const JPGLibrary&) = delete;
JPGLibrary& operator=(JPGLibrary&&) = delete;
};
#endif
#endif // IMAGE_SUPPORT

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -16,28 +16,27 @@
//============================================================================
#include "JoyMap.hxx"
#include "jsonDefinitions.hxx"
#include "Logger.hxx"
#include "jsonDefinitions.hxx"
using json = nlohmann::json;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::add(const Event::Type event, const JoyMapping& mapping)
void JoyMap::add(Event::Type event, const JoyMapping& mapping)
{
myMap[mapping] = event;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir,
const int hat, const JoyHatDir hdir)
void JoyMap::add(Event::Type event, EventMode mode, int button,
JoyAxis axis, JoyDir adir, int hat, JoyHatDir hdir)
{
add(event, JoyMapping(mode, button, axis, adir, hat, hdir));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
const int hat, const JoyHatDir hdir)
void JoyMap::add(Event::Type event, EventMode mode, int button,
int hat, JoyHatDir hdir)
{
add(event, JoyMapping(mode, button, hat, hdir));
}
@ -49,15 +48,13 @@ void JoyMap::erase(const JoyMapping& mapping)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::erase(const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir)
void JoyMap::erase(EventMode mode, int button, JoyAxis axis, JoyDir adir)
{
erase(JoyMapping(mode, button, axis, adir));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::erase(const EventMode mode, const int button,
const int hat, const JoyHatDir hdir)
void JoyMap::erase(EventMode mode, int button, int hat, JoyHatDir hdir)
{
erase(JoyMapping(mode, button, hat, hdir));
}
@ -82,15 +79,15 @@ Event::Type JoyMap::get(const JoyMapping& mapping) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Type JoyMap::get(const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir) const
Event::Type JoyMap::get(EventMode mode, int button,
JoyAxis axis, JoyDir adir) const
{
return get(JoyMapping(mode, button, axis, adir));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Type JoyMap::get(const EventMode mode, const int button,
const int hat, const JoyHatDir hdir) const
Event::Type JoyMap::get(EventMode mode, int button,
int hat, JoyHatDir hdir) const
{
return get(JoyMapping(mode, button, hat, hdir));
}
@ -98,21 +95,18 @@ Event::Type JoyMap::get(const EventMode mode, const int button,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool JoyMap::check(const JoyMapping& mapping) const
{
const auto find = myMap.find(mapping);
return (find != myMap.end());
return myMap.contains(mapping);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool JoyMap::check(const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir,
const int hat, const JoyHatDir hdir) const
bool JoyMap::check(EventMode mode, int button, JoyAxis axis, JoyDir adir,
int hat, JoyHatDir hdir) const
{
return check(JoyMapping(mode, button, axis, adir, hat, hdir));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
string JoyMap::getDesc(Event::Type event, const JoyMapping& mapping)
{
ostringstream buf;
@ -158,7 +152,8 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const
string JoyMap::getEventMappingDesc(int stick, Event::Type event,
EventMode mode) const
{
ostringstream buf;
@ -166,7 +161,7 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
{
if (_event == event && _mapping.mode == mode)
{
if(buf.str() != "")
if(!buf.view().empty())
buf << ", ";
buf << "C" << stick << getDesc(event, _mapping);
}
@ -175,7 +170,8 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const EventMode mode) const
JoyMap::JoyMappingArray JoyMap::getEventMapping(Event::Type event,
EventMode mode) const
{
JoyMappingArray map;
@ -187,32 +183,31 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json JoyMap::saveMapping(const EventMode mode) const
json JoyMap::saveMapping(EventMode mode) const
{
using MapType = std::pair<JoyMapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.button != b.first.button)
return a.first.button < b.first.button;
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.button != b.first.button)
return a.first.button < b.first.button;
if(a.first.axis != b.first.axis)
return a.first.axis < b.first.axis;
if(a.first.axis != b.first.axis)
return a.first.axis < b.first.axis;
if(a.first.adir != b.first.adir)
return a.first.adir < b.first.adir;
if(a.first.adir != b.first.adir)
return a.first.adir < b.first.adir;
if(a.first.hat != b.first.hat)
return a.first.hat < b.first.hat;
if(a.first.hat != b.first.hat)
return a.first.hat < b.first.hat;
if(a.first.hdir != b.first.hdir)
return a.first.hdir < b.first.hdir;
if(a.first.hdir != b.first.hdir)
return a.first.hdir < b.first.hdir;
return a.second < b.second;
}
return a.second < b.second;
}
);
json eventMappings = json::array();
@ -243,16 +238,26 @@ json JoyMap::saveMapping(const EventMode mode) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
int JoyMap::loadMapping(const json& eventMappings, EventMode mode)
{
int i = 0;
for(const json& eventMapping : eventMappings) {
int button = eventMapping.contains("button") ? eventMapping.at("button").get<int>() : JOY_CTRL_NONE;
JoyAxis axis = eventMapping.contains("axis") ? eventMapping.at("axis").get<JoyAxis>() : JoyAxis::NONE;
JoyDir axisDirection = eventMapping.contains("axis") ? eventMapping.at("axisDirection").get<JoyDir>() : JoyDir::NONE;
int hat = eventMapping.contains("hat") ? eventMapping.at("hat").get<int>() : -1;
JoyHatDir hatDirection = eventMapping.contains("hat") ? eventMapping.at("hatDirection").get<JoyHatDir>() : JoyHatDir::CENTER;
const int button = eventMapping.contains("button")
? eventMapping.at("button").get<int>()
: JOY_CTRL_NONE;
const JoyAxis axis = eventMapping.contains("axis")
? eventMapping.at("axis").get<JoyAxis>()
: JoyAxis::NONE;
const JoyDir axisDirection = eventMapping.contains("axis")
? eventMapping.at("axisDirection").get<JoyDir>()
: JoyDir::NONE;
const int hat = eventMapping.contains("hat")
? eventMapping.at("hat").get<int>()
: -1;
const JoyHatDir hatDirection = eventMapping.contains("hat")
? eventMapping.at("hatDirection").get<JoyHatDir>()
: JoyHatDir::CENTER;
try {
// avoid blocking mappings for NoType events
@ -279,17 +284,17 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json JoyMap::convertLegacyMapping(string list)
json JoyMap::convertLegacyMapping(string lst)
{
json eventMappings = json::array();
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::replace(list.begin(), list.end(), '|', ' ');
std::replace(list.begin(), list.end(), ':', ' ');
std::replace(list.begin(), list.end(), ',', ' ');
std::ranges::replace(lst, '|', ' ');
std::ranges::replace(lst, ':', ' ');
std::ranges::replace(lst, ',', ' ');
istringstream buf(list);
istringstream buf(lst);
int event = 0, button = 0, axis = 0, adir = 0, hat = 0, hdir = 0;
while(buf >> event && buf >> button
@ -298,18 +303,18 @@ json JoyMap::convertLegacyMapping(string list)
{
json eventMapping = json::object();
eventMapping["event"] = Event::Type(event);
eventMapping["event"] = static_cast<Event::Type>(event);
if(button != JOY_CTRL_NONE) eventMapping["button"] = button;
if(static_cast<JoyAxis>(axis) != JoyAxis::NONE) {
eventMapping["axis"] = JoyAxis(axis);
eventMapping["axisDirection"] = JoyDir(adir);
eventMapping["axis"] = static_cast<JoyAxis>(axis);
eventMapping["axisDirection"] = static_cast<JoyDir>(adir);
}
if(hat != -1) {
eventMapping["hat"] = hat;
eventMapping["hatDirection"] = JoyHatDir(hdir);
eventMapping["hatDirection"] = static_cast<JoyHatDir>(hdir);
}
eventMappings.push_back(eventMapping);
@ -319,7 +324,7 @@ json JoyMap::convertLegacyMapping(string list)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::eraseMode(const EventMode mode)
void JoyMap::eraseMode(EventMode mode)
{
for(auto item = myMap.begin(); item != myMap.end();)
if(item->first.mode == mode) {
@ -330,7 +335,7 @@ void JoyMap::eraseMode(const EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::eraseEvent(const Event::Type event, const EventMode mode)
void JoyMap::eraseEvent(Event::Type event, EventMode mode)
{
for(auto item = myMap.begin(); item != myMap.end();)
if(item->second == event && item->first.mode == mode) {

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -58,6 +58,7 @@ class JoyMap
axis{JoyAxis::NONE}, adir{JoyDir::NONE},
hat{c_hat}, hdir{c_hdir} { }
~JoyMapping() = default;
JoyMapping(const JoyMapping&) = default;
JoyMapping& operator=(const JoyMapping&) = default;
JoyMapping(JoyMapping&&) = default;
@ -77,64 +78,61 @@ class JoyMap
using JoyMappingArray = std::vector<JoyMapping>;
JoyMap() = default;
~JoyMap() = default;
/** Add new mapping for given event */
void add(const Event::Type event, const JoyMapping& mapping);
void add(const Event::Type event, const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir,
const int hat = JOY_CTRL_NONE, const JoyHatDir hdir = JoyHatDir::CENTER);
void add(const Event::Type event, const EventMode mode, const int button,
const int hat, const JoyHatDir hdir);
void add(Event::Type event, const JoyMapping& mapping);
void add(Event::Type event, EventMode mode, int button,
JoyAxis axis, JoyDir adir,
int hat = JOY_CTRL_NONE, JoyHatDir hdir = JoyHatDir::CENTER);
void add(Event::Type event, EventMode mode, int button,
int hat, JoyHatDir hdir);
/** Erase mapping */
void erase(const JoyMapping& mapping);
void erase(const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir);
void erase(const EventMode mode, const int button,
const int hat, const JoyHatDir hdir);
void erase(EventMode mode, int button, JoyAxis axis, JoyDir adir);
void erase(EventMode mode, int button, int hat, JoyHatDir hdir);
/** Get event for mapping */
Event::Type get(const JoyMapping& mapping) const;
Event::Type get(const EventMode mode, const int button,
const JoyAxis axis = JoyAxis::NONE, const JoyDir adir = JoyDir::NONE) const;
Event::Type get(const EventMode mode, const int button,
const int hat, const JoyHatDir hdir) const;
Event::Type get(EventMode mode, int button, JoyAxis axis = JoyAxis::NONE,
JoyDir adir = JoyDir::NONE) const;
Event::Type get(EventMode mode, int button, int hat, JoyHatDir hdir) const;
/** Check if a mapping exists */
bool check(const JoyMapping& mapping) const;
bool check(const EventMode mode, const int button,
const JoyAxis axis, const JoyDir adir,
const int hat = JOY_CTRL_NONE, const JoyHatDir hdir = JoyHatDir::CENTER) const;
bool check(EventMode mode, int button, JoyAxis axis, JoyDir adir,
int hat = JOY_CTRL_NONE, JoyHatDir hdir = JoyHatDir::CENTER) const;
/** Get mapping description */
string getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const;
string getEventMappingDesc(int stick, Event::Type event, EventMode mode) const;
JoyMappingArray getEventMapping(const Event::Type event, const EventMode mode) const;
JoyMappingArray getEventMapping(Event::Type event, EventMode mode) const;
nlohmann::json saveMapping(const EventMode mode) const;
int loadMapping(const nlohmann::json& eventMappings, const EventMode mode);
nlohmann::json saveMapping(EventMode mode) const;
int loadMapping(const nlohmann::json& eventMappings, EventMode mode);
static nlohmann::json convertLegacyMapping(string list);
static nlohmann::json convertLegacyMapping(string lst);
/** Erase all mappings for given mode */
void eraseMode(const EventMode mode);
void eraseMode(EventMode mode);
/** Erase given event's mapping for given mode */
void eraseEvent(const Event::Type event, const EventMode mode);
void eraseEvent(Event::Type event, EventMode mode);
/** clear all mappings for a modes */
// void clear() { myMap.clear(); }
size_t size() { return myMap.size(); }
size_t size() const { return myMap.size(); }
private:
string getDesc(const Event::Type event, const JoyMapping& mapping) const;
static string getDesc(Event::Type event, const JoyMapping& mapping);
struct JoyHash {
size_t operator()(const JoyMapping& m)const {
return std::hash<uInt64>()((uInt64(m.mode)) // 3 bits
+ ((uInt64(m.button)) * 7) // 3 bits
+ (((uInt64(m.axis)) << 0) // 2 bits
| ((uInt64(m.adir)) << 2) // 2 bits
| ((uInt64(m.hat )) << 4) // 1 bit
| ((uInt64(m.hdir)) << 5) // 2 bits
return std::hash<uInt64>()((static_cast<uInt64>(m.mode)) // 3 bits
+ ((static_cast<uInt64>(m.button)) * 7) // 3 bits
+ (((static_cast<uInt64>(m.axis)) << 0) // 3 bits
| ((static_cast<uInt64>(m.adir)) << 3) // 2 bits
| ((static_cast<uInt64>(m.hat )) << 5) // 1 bit
| ((static_cast<uInt64>(m.hdir)) << 6) // 2 bits
) * 61
);
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -18,18 +18,17 @@
#include "KeyMap.hxx"
#include "Logger.hxx"
#include "jsonDefinitions.hxx"
#include <map>
using json = nlohmann::json;
namespace {
json serializeModkeyMask(int mask)
{
if(mask == StellaMod::KBDM_NONE) return json(nullptr);
if(mask == StellaMod::KBDM_NONE) return {};
json serializedMask = json::array();
for(StellaMod mod: {
for(const StellaMod mod: {
StellaMod::KBDM_CTRL,
StellaMod::KBDM_SHIFT,
StellaMod::KBDM_ALT,
@ -66,16 +65,16 @@ namespace {
return mask;
}
}
} // namespace
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::add(const Event::Type event, const Mapping& mapping)
void KeyMap::add(Event::Type event, const Mapping& mapping)
{
myMap[convertMod(mapping)] = event;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::add(const Event::Type event, const EventMode mode, const int key, const int mod)
void KeyMap::add(Event::Type event, EventMode mode, int key, int mod)
{
add(event, Mapping(mode, key, mod));
}
@ -87,7 +86,7 @@ void KeyMap::erase(const Mapping& mapping)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::erase(const EventMode mode, const int key, const int mod)
void KeyMap::erase(EventMode mode, int key, int mod)
{
erase(Mapping(mode, key, mod));
}
@ -115,7 +114,7 @@ Event::Type KeyMap::get(const Mapping& mapping) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) const
Event::Type KeyMap::get(EventMode mode, int key, int mod) const
{
return get(Mapping(mode, key, mod));
}
@ -123,19 +122,17 @@ Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) cons
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KeyMap::check(const Mapping& mapping) const
{
const auto find = myMap.find(convertMod(mapping));
return (find != myMap.end());
return myMap.contains(convertMod(mapping));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool KeyMap::check(const EventMode mode, const int key, const int mod) const
bool KeyMap::check(EventMode mode, int key, int mod) const
{
return check(Mapping(mode, key, mod));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string KeyMap::getDesc(const Mapping& mapping) const
string KeyMap::getDesc(const Mapping& mapping)
{
ostringstream buf;
#if defined(BSPF_MACOS) || defined(MACOS_KEYS)
@ -184,13 +181,13 @@ string KeyMap::getDesc(const Mapping& mapping) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string KeyMap::getDesc(const EventMode mode, const int key, const int mod) const
string KeyMap::getDesc(EventMode mode, int key, int mod)
{
return getDesc(Mapping(mode, key, mod));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode) const
string KeyMap::getEventMappingDesc(Event::Type event, EventMode mode) const
{
ostringstream buf;
@ -198,7 +195,7 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
{
if (_event == event && _mapping.mode == mode)
{
if(buf.str() != "")
if(!buf.view().empty())
buf << ", ";
buf << getDesc(_mapping);
}
@ -207,25 +204,25 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const EventMode mode) const
KeyMap::MappingArray KeyMap::getEventMapping(Event::Type event,
EventMode mode) const
{
MappingArray map;
MappingArray ma;
for (const auto& [_mapping, _event]: myMap)
if (_event == event && _mapping.mode == mode)
map.push_back(_mapping);
ma.push_back(_mapping);
return map;
return ma;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json KeyMap::saveMapping(const EventMode mode) const
json KeyMap::saveMapping(EventMode mode) const
{
using MapType = std::pair<Mapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.key != b.first.key)
@ -258,7 +255,8 @@ json KeyMap::saveMapping(const EventMode mode) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
int KeyMap::loadMapping(const json& mappings, EventMode mode)
{
int i = 0;
for(const json& mapping : mappings)
@ -285,27 +283,28 @@ int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json KeyMap::convertLegacyMapping(string list)
json KeyMap::convertLegacyMapping(string_view lm)
{
json convertedMapping = json::array();
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::replace(list.begin(), list.end(), '|', ' ');
std::replace(list.begin(), list.end(), ':', ' ');
std::replace(list.begin(), list.end(), ',', ' ');
istringstream buf(list);
string lst{lm};
std::ranges::replace(lst, '|', ' ');
std::ranges::replace(lst, ':', ' ');
std::ranges::replace(lst, ',', ' ');
istringstream buf(lst);
int event = 0, key = 0, mod = 0;
while(buf >> event && buf >> key && buf >> mod)
{
json mapping = json::object();
mapping["event"] = Event::Type(event);
mapping["key"] = StellaKey(key);
mapping["event"] = static_cast<Event::Type>(event);
mapping["key"] = static_cast<StellaKey>(key);
if(StellaMod(mod) != StellaMod::KBDM_NONE)
mapping["mod"] = serializeModkeyMask(StellaMod(mod));
if(static_cast<StellaMod>(mod) != StellaMod::KBDM_NONE)
mapping["mod"] = serializeModkeyMask(static_cast<StellaMod>(mod));
convertedMapping.push_back(mapping);
}
@ -314,7 +313,7 @@ json KeyMap::convertLegacyMapping(string list)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::eraseMode(const EventMode mode)
void KeyMap::eraseMode(EventMode mode)
{
for(auto item = myMap.begin(); item != myMap.end();)
if(item->first.mode == mode) {
@ -325,7 +324,7 @@ void KeyMap::eraseMode(const EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
void KeyMap::eraseEvent(Event::Type event, EventMode mode)
{
for(auto item = myMap.begin(); item != myMap.end();)
if(item->second == event && item->first.mode == mode) {
@ -336,7 +335,7 @@ void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping) const
KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping)
{
Mapping m = mapping;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -42,6 +42,7 @@ class KeyMap
: mode{c_mode}, key{c_key}, mod{c_mod} { }
explicit Mapping(EventMode c_mode, int c_key, int c_mod)
: mode{c_mode}, key{static_cast<StellaKey>(c_key)}, mod{static_cast<StellaMod>(c_mod)} { }
~Mapping() = default;
Mapping(const Mapping&) = default;
Mapping& operator=(const Mapping&) = default;
Mapping(Mapping&&) = default;
@ -61,41 +62,42 @@ class KeyMap
using MappingArray = std::vector<Mapping>;
KeyMap() = default;
~KeyMap() = default;
/** Add new mapping for given event */
void add(const Event::Type event, const Mapping& mapping);
void add(const Event::Type event, const EventMode mode, const int key, const int mod);
void add(Event::Type event, const Mapping& mapping);
void add(Event::Type event, EventMode mode, int key, int mod);
/** Erase mapping */
void erase(const Mapping& mapping);
void erase(const EventMode mode, const int key, const int mod);
void erase(EventMode mode, int key, int mod);
/** Get event for mapping */
Event::Type get(const Mapping& mapping) const;
Event::Type get(const EventMode mode, const int key, const int mod) const;
Event::Type get(EventMode mode, int key, int mod) const;
/** Check if a mapping exists */
bool check(const Mapping& mapping) const;
bool check(const EventMode mode, const int key, const int mod) const;
bool check(EventMode mode, int key, int mod) const;
/** Get mapping description */
string getDesc(const Mapping& mapping) const;
string getDesc(const EventMode mode, const int key, const int mod) const;
static string getDesc(const Mapping& mapping);
static string getDesc(EventMode mode, int key, int mod);
/** Get the mapping description(s) for given event and mode */
string getEventMappingDesc(const Event::Type event, const EventMode mode) const;
string getEventMappingDesc(Event::Type event, EventMode mode) const;
MappingArray getEventMapping(const Event::Type event, const EventMode mode) const;
MappingArray getEventMapping(Event::Type event, EventMode mode) const;
nlohmann::json saveMapping(const EventMode mode) const;
int loadMapping(const nlohmann::json& mapping, const EventMode mode);
nlohmann::json saveMapping(EventMode mode) const;
int loadMapping(const nlohmann::json& mapping, EventMode mode);
static nlohmann::json convertLegacyMapping(string list);
static nlohmann::json convertLegacyMapping(string_view lm);
/** Erase all mappings for given mode */
void eraseMode(const EventMode mode);
void eraseMode(EventMode mode);
/** Erase given event's mapping for given mode */
void eraseEvent(const Event::Type event, const EventMode mode);
void eraseEvent(Event::Type event, EventMode mode);
/** clear all mappings for a modes */
// void clear() { myMap.clear(); }
size_t size() { return myMap.size(); }
@ -104,16 +106,16 @@ class KeyMap
private:
//** Convert modifiers */
Mapping convertMod(const Mapping& mapping) const;
static Mapping convertMod(const Mapping& mapping);
struct KeyHash {
size_t operator()(const Mapping& m) const {
return std::hash<uInt64>()((uInt64(m.mode)) // 3 bits
+ ((uInt64(m.key)) * 7) // 8 bits
+ (((uInt64((m.mod & KBDM_SHIFT) != 0) << 0)) // 1 bit
| ((uInt64((m.mod & KBDM_ALT ) != 0) << 1)) // 1 bit
| ((uInt64((m.mod & KBDM_GUI ) != 0) << 2)) // 1 bit
| ((uInt64((m.mod & KBDM_CTRL ) != 0) << 3)) // 1 bit
return std::hash<uInt64>()((static_cast<uInt64>(m.mode)) // 3 bits
+ ((static_cast<uInt64>(m.key)) * 7) // 8 bits
+ (((static_cast<uInt64>((m.mod & KBDM_SHIFT) != 0) << 0)) // 1 bit
| ((static_cast<uInt64>((m.mod & KBDM_ALT ) != 0) << 1)) // 1 bit
| ((static_cast<uInt64>((m.mod & KBDM_GUI ) != 0) << 2)) // 1 bit
| ((static_cast<uInt64>((m.mod & KBDM_CTRL ) != 0) << 3)) // 1 bit
) * 2047
);
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -59,7 +59,8 @@ class LinkedObjectPool
/*
Create a pool of size CAPACITY; the active list starts out empty.
*/
LinkedObjectPool<T, CAPACITY>() { resize(CAPACITY); }
LinkedObjectPool() { resize(CAPACITY); }
~LinkedObjectPool() = default;
/**
Return node data that the 'current' iterator points to.
@ -287,6 +288,6 @@ class LinkedObjectPool
LinkedObjectPool& operator=(LinkedObjectPool&&) = delete;
};
} // Namespace Common
} // namespace Common
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -26,44 +26,46 @@ Logger& Logger::instance()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Logger::log(const string& message, Level level)
void Logger::log(string_view message, Level level)
{
instance().logMessage(message, level);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Logger::error(const string& message)
void Logger::error(string_view message)
{
instance().logMessage(message, Level::ERR);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Logger::info(const string& message)
void Logger::info(string_view message)
{
instance().logMessage(message, Level::INFO);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Logger::debug(const string& message)
void Logger::debug(string_view message)
{
instance().logMessage(message, Level::DEBUG);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Logger::logMessage(const string& message, Level level)
void Logger::logMessage(string_view message, Level level)
{
std::lock_guard<std::mutex> lock(mutex);
const std::lock_guard<std::mutex> lock(mutex);
if(level == Logger::Level::ERR)
{
cout << message << endl << std::flush;
myLogMessages += message + "\n";
cout << message << '\n' << std::flush;
myLogMessages += message;
myLogMessages += "\n";
}
else if(static_cast<int>(level) <= myLogLevel ||
level == Logger::Level::ALWAYS)
{
if(myLogToConsole)
cout << message << endl << std::flush;
myLogMessages += message + "\n";
cout << message << '\n' << std::flush;
myLogMessages += message;
myLogMessages += "\n";
}
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -27,7 +27,7 @@ class Logger {
public:
enum class Level {
enum class Level: uInt8 {
ERR = 0, // cannot use ERROR???
INFO = 1,
DEBUG = 2,
@ -40,13 +40,13 @@ class Logger {
static Logger& instance();
static void log(const string& message, Level level = Level::ALWAYS);
static void log(string_view message, Level level = Level::ALWAYS);
static void error(const string& message);
static void error(string_view message);
static void info(const string& message);
static void info(string_view message);
static void debug(const string& message);
static void debug(string_view message);
void setLogParameters(int logLevel, bool logToConsole);
void setLogParameters(Level logLevel, bool logToConsole);
@ -55,6 +55,7 @@ class Logger {
protected:
Logger() = default;
~Logger() = default;
private:
int myLogLevel{static_cast<int>(Level::MAX)};
@ -66,7 +67,7 @@ class Logger {
std::mutex mutex;
private:
void logMessage(const string& message, Level level);
void logMessage(string_view message, Level level);
Logger(const Logger&) = delete;
Logger(Logger&&) = delete;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -181,6 +181,15 @@ class MediaFactory
#endif
}
static bool supportsURL()
{
#if defined(SDL_SUPPORT)
return SDLSupportsURL();
#else
return false;
#endif
}
static bool openURL(const string& url)
{
#if defined(SDL_SUPPORT)
@ -193,6 +202,7 @@ class MediaFactory
private:
// Following constructors and assignment operators not supported
MediaFactory() = delete;
~MediaFactory() = delete;
MediaFactory(const MediaFactory&) = delete;
MediaFactory(MediaFactory&&) = delete;
MediaFactory& operator=(const MediaFactory&) = delete;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -23,12 +23,12 @@
#include "MouseControl.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MouseControl::MouseControl(Console& console, const string& mode)
MouseControl::MouseControl(Console& console, string_view mode)
: myProps{console.properties()},
myLeftController{console.leftController()},
myRightController{console.rightController()}
{
istringstream m_axis(mode);
istringstream m_axis(string{mode}); // TODO: fixed in C++20
string m_mode;
m_axis >> m_mode;
@ -41,8 +41,10 @@ MouseControl::MouseControl(Console& console, const string& mode)
m_mode[0] >= '0' && m_mode[0] <= '8' &&
m_mode[1] >= '0' && m_mode[1] <= '8')
{
const MouseControl::Type xaxis = static_cast<MouseControl::Type>(static_cast<int>(m_mode[0]) - '0');
const MouseControl::Type yaxis = static_cast<MouseControl::Type>(static_cast<int>(m_mode[1]) - '0');
const auto xaxis = static_cast<MouseControl::Type>
(static_cast<int>(m_mode[0]) - '0');
const auto yaxis = static_cast<MouseControl::Type>
(static_cast<int>(m_mode[1]) - '0');
ostringstream msg;
Controller::Type xtype = Controller::Type::Joystick, ytype = Controller::Type::Joystick;
int xid = -1, yid = -1;
@ -51,49 +53,52 @@ MouseControl::MouseControl(Console& console, const string& mode)
Controller::Type& type, int& id) {
switch(axis)
{
case MouseControl::Type::NoControl:
using enum MouseControl::Type;
case NoControl:
msg << "not used";
break;
case MouseControl::Type::LeftPaddleA:
case LeftPaddleA:
type = Controller::Type::Paddles;
id = 0;
msg << "Left Paddle A";
break;
case MouseControl::Type::LeftPaddleB:
case LeftPaddleB:
type = Controller::Type::Paddles;
id = 1;
msg << "Left Paddle B";
break;
case MouseControl::Type::RightPaddleA:
case RightPaddleA:
type = Controller::Type::Paddles;
id = 2;
msg << "Right Paddle A";
break;
case MouseControl::Type::RightPaddleB:
case RightPaddleB:
type = Controller::Type::Paddles;
id = 3;
msg << "Right Paddle B";
break;
case MouseControl::Type::LeftDriving:
case LeftDriving:
type = Controller::Type::Driving;
id = 0;
msg << "Left Driving";
break;
case MouseControl::Type::RightDriving:
case RightDriving:
type = Controller::Type::Driving;
id = 1;
msg << "Right Driving";
break;
case MouseControl::Type::LeftMindLink:
case LeftMindLink:
type = Controller::Type::MindLink;
id = 0;
msg << "Left MindLink";
break;
case MouseControl::Type::RightMindLink:
case RightMindLink:
type = Controller::Type::MindLink;
id = 1;
msg << "Right MindLink";
break;
default:
break; // Not supposed to get here
}
};
@ -102,7 +107,7 @@ MouseControl::MouseControl(Console& console, const string& mode)
msg << ", Y-axis is ";
MControlToController(yaxis, ytype, yid);
myModeList.emplace_back(xtype, xid, ytype, yid, msg.str());
myModeList.emplace_back(xtype, xid, ytype, yid, msg.view());
}
// Now consider the possible modes for the mouse based on the left
@ -127,12 +132,12 @@ MouseControl::MouseControl(Console& console, const string& mode)
Paddles::setDigitalPaddleRange(m_range);
// If the mouse isn't used at all, we still need one item in the list
if(myModeList.size() == 0)
if(myModeList.empty())
myModeList.emplace_back("Mouse not used for current controllers");
#if 0
for(const auto& m: myModeList)
cerr << m << endl;
cerr << m << '\n';
#endif
}
@ -167,9 +172,9 @@ void MouseControl::addLeftControllerModes(bool noswap)
{
ostringstream msg;
msg << "Mouse is left " << myLeftController.name() << " controller";
Controller::Type type = myLeftController.type();
int id = noswap ? 0 : 1;
myModeList.emplace_back(type, id, type, id, msg.str());
const Controller::Type type = myLeftController.type();
const int id = noswap ? 0 : 1;
myModeList.emplace_back(type, id, type, id, msg.view());
}
}
}
@ -188,9 +193,9 @@ void MouseControl::addRightControllerModes(bool noswap)
{
ostringstream msg;
msg << "Mouse is right " << myRightController.name() << " controller";
Controller::Type type = myRightController.type();
int id = noswap ? 1 : 0;
myModeList.emplace_back(type, id, type, id, msg.str());
const Controller::Type type = myRightController.type();
const int id = noswap ? 1 : 0;
myModeList.emplace_back(type, id, type, id, msg.view());
}
}
}
@ -201,11 +206,11 @@ void MouseControl::addPaddleModes(int lport, int rport, int lname, int rname)
const Controller::Type type = Controller::Type::Paddles;
ostringstream msg;
msg << "Mouse is Paddle " << lname << " controller";
const MouseMode mode0(type, lport, type, lport, msg.str());
const MouseMode mode0(type, lport, type, lport, msg.view());
msg.str("");
msg << "Mouse is Paddle " << rname << " controller";
const MouseMode mode1(type, rport, type, rport, msg.str());
const MouseMode mode1(type, rport, type, rport, msg.view());
if(BSPF::equalsIgnoreCase(myProps.get(PropType::Controller_SwapPaddles), "NO"))
{

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -19,9 +19,9 @@
#define MOUSE_CONTROL_HXX
class Console;
class Controller;
class Properties;
#include "Control.hxx"
#include "bspf.hxx"
/**
@ -41,7 +41,7 @@ class MouseControl
/**
Enumeration of mouse axis control types
*/
enum class Type
enum class Type: uInt8
{
LeftPaddleA = 0, LeftPaddleB, RightPaddleA, RightPaddleB,
LeftDriving, RightDriving, LeftMindLink, RightMindLink,
@ -55,7 +55,8 @@ class MouseControl
@param console The console in use by the system
@param mode Contains information about how to use the mouse axes/buttons
*/
MouseControl(Console& console, const string& mode);
MouseControl(Console& console, string_view mode);
~MouseControl() = default;
/**
Cycle through each available mouse control mode
@ -73,7 +74,7 @@ class MouseControl
void addLeftControllerModes(bool noswap);
void addRightControllerModes(bool noswap);
void addPaddleModes(int lport, int rport, int lname, int rname);
bool controllerSupportsMouse(Controller& controller);
static bool controllerSupportsMouse(Controller& controller);
private:
const Properties& myProps;
@ -85,10 +86,10 @@ class MouseControl
int xid{-1}, yid{-1};
string message;
explicit MouseMode(const string& msg = "") : message{msg} { }
explicit MouseMode(string_view msg = "") : message{msg} { }
MouseMode(Controller::Type xt, int xi,
Controller::Type yt, int yi,
const string& msg)
string_view msg)
: xtype{xt}, ytype{yt}, xid{xi}, yid{yi}, message{msg} { }
friend ostream& operator<<(ostream& os, const MouseMode& mm)

View File

@ -8,19 +8,16 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 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 "Logger.hxx"
#include "OSystem.hxx"
#include "Console.hxx"
#include "Joystick.hxx"
#include "Paddles.hxx"
#include "MindLink.hxx"
#include "PointingDevice.hxx"
#include "Driving.hxx"
#include "Settings.hxx"
@ -48,7 +45,7 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
}
json mappings;
const string& serializedMapping = myOSystem.settings().getString("joymap");
const string_view serializedMapping = myOSystem.settings().getString("joymap");
try {
mappings = json::parse(serializedMapping);
@ -69,11 +66,11 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json PhysicalJoystickHandler::convertLegacyMapping(const string& mapping)
json PhysicalJoystickHandler::convertLegacyMapping(string_view mapping)
{
constexpr char CTRL_DELIM = '^';
istringstream buf(mapping);
istringstream buf(string{mapping}); // TODO: fixed in C++20
string joymap, joyname;
getline(buf, joymap, CTRL_DELIM); // event list size, ignore
@ -120,7 +117,7 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
{
ostringstream name;
name << stick->name << " #" << count+1;
stick->name = name.str();
stick->name = name.view();
}
stick->type = PhysicalJoystick::Type::REGULAR;
}
@ -149,11 +146,9 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
// We're potentially swapping out an input device behind the back of
// the Event system, so we make sure all Stelladaptor-generated events
// are reset
for(int port = 0; port < NUM_PORTS; ++port)
{
for(int axis = 0; axis < NUM_SA_AXIS; ++axis)
for(int port = 0; port < NUM_PORTS; ++port) // NOLINT
for(int axis = 0; axis < NUM_SA_AXIS; ++axis) // NOLINT
myEvent.set(SA_Axis[port][axis], 0);
}
return stick->ID;
}
@ -171,16 +166,16 @@ void PhysicalJoystickHandler::addToDatabase(const PhysicalJoystickPtr& stick)
}
else // adding for the first time
{
StickInfo info("", stick);
const StickInfo info("", stick);
myDatabase.emplace(stick->name, info);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kMenuMode);
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kEmulationMode);
}
ostringstream buf;
buf << "Added joystick " << stick->ID << ":" << endl
<< " " << stick->about() << endl;
Logger::info(buf.str());
buf << "Added joystick " << stick->ID << ":\n"
<< " " << stick->about() << '\n';
Logger::info(buf.view());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -193,15 +188,15 @@ bool PhysicalJoystickHandler::remove(int id)
// So we use the 'active' joystick list to access them
try
{
PhysicalJoystickPtr stick = mySticks.at(id);
const PhysicalJoystickPtr stick = mySticks.at(id);
const auto it = myDatabase.find(stick->name);
if(it != myDatabase.end() && it->second.joy == stick)
{
ostringstream buf;
buf << "Removed joystick " << mySticks[id]->ID << ":" << endl
<< " " << mySticks[id]->about() << endl;
Logger::info(buf.str());
buf << "Removed joystick " << mySticks[id]->ID << ":\n"
<< " " << mySticks[id]->about() << '\n';
Logger::info(buf.view());
// Remove joystick, but remember mapping
it->second.mapping = stick->getMap();
@ -213,14 +208,13 @@ bool PhysicalJoystickHandler::remove(int id)
}
catch(const std::out_of_range&)
{
// fall through to indicate remove failed
return false;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::remove(const string& name)
bool PhysicalJoystickHandler::remove(string_view name)
{
const auto it = myDatabase.find(name);
if(it != myDatabase.end() && it->second.joy == nullptr)
@ -232,7 +226,18 @@ bool PhysicalJoystickHandler::remove(const string& name)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
void PhysicalJoystickHandler::setPort(string_view name, PhysicalJoystick::Port port)
{
const auto it = myDatabase.find(name);
if(it != myDatabase.end() && it->second.joy != nullptr)
{
it->second.joy->setPort(port);
// TODO: update mappings
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::mapStelladaptors(string_view saport, int ID)
{
bool erased = false;
// saport will have two values:
@ -257,9 +262,9 @@ bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
{
// Erase a previously added Stelladapter with a higher ID
ostringstream buf;
buf << "Erased joystick " << _stick->ID << ":" << endl
<< " " << _stick->about() << endl;
Logger::info(buf.str());
buf << "Erased joystick " << _stick->ID << ":\n"
<< " " << _stick->about() << '\n';
Logger::info(buf.view());
_stick->name.erase(pos);
erased = true;
@ -300,7 +305,7 @@ bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::hasStelladaptors() const
{
for(auto& [_id, _joyptr] : mySticks)
for(const auto& [_id, _joyptr] : mySticks)
{
// remove previously added emulated ports
const size_t pos = _joyptr->name.find(" (emulates ");
@ -321,8 +326,7 @@ bool PhysicalJoystickHandler::hasStelladaptors() const
// 2. reset all events to default (event == Event::NoType, updateDefault == false)
// 3. reset one event to default (event != Event::NoType)
void PhysicalJoystickHandler::setDefaultAction(int stick,
EventMapping map, Event::Type event,
EventMode mode, bool updateDefaults)
EventMapping map, Event::Type event, EventMode mode, bool updateDefaults)
{
const PhysicalJoystickPtr j = joy(stick);
@ -334,7 +338,7 @@ void PhysicalJoystickHandler::setDefaultAction(int stick,
{
// if there is no existing mapping for the event and
// the default mapping for the event is unused, set default key for event
if(j->joyMap.getEventMapping(map.event, mode).size() == 0 &&
if(j->joyMap.getEventMapping(map.event, mode).empty() &&
!j->joyMap.check(mode, map.button, map.axis, map.adir, map.hat, map.hdir))
{
if (map.hat == JOY_CTRL_NONE)
@ -355,50 +359,57 @@ void PhysicalJoystickHandler::setDefaultAction(int stick,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type event,
EventMode mode, bool updateDefaults)
void PhysicalJoystickHandler::setStickDefaultMapping(
int stick, Event::Type event, EventMode mode, bool updateDefaults)
{
const PhysicalJoystickPtr j = joy(stick);
if(j)
{
switch (mode)
switch(mode)
{
case EventMode::kEmulationMode:
{
// A regular joystick defaults to left or right based on the
// stick number being even or odd; 'daptor joysticks request a
// specific port
const bool useLeftMappings =
j->type == PhysicalJoystick::Type::REGULAR ? ((stick % 2) == 0) :
(j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR);
// A regular joystick defaults to left or right based on
// the defined port or stick number being even or odd;
// 'daptor' joysticks request a specific port
bool useLeftMappings = true;
if(j->type == PhysicalJoystick::Type::REGULAR)
{
useLeftMappings = j->port == PhysicalJoystick::Port::LEFT
|| (j->port == PhysicalJoystick::Port::AUTO && (stick % 2) == 0);
}
else
useLeftMappings =
j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR;
if(useLeftMappings)
{
// put all controller events into their own mode's mappings
for (const auto& item : DefaultLeftJoystickMapping)
for(const auto& item : DefaultLeftJoystickMapping)
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
for (const auto& item : DefaultLeftKeyboardMapping)
for(const auto& item : DefaultLeftKeyboardMapping)
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
for (const auto& item : DefaultLeftDrivingMapping)
for(const auto& item : DefaultLeftDrivingMapping)
setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults);
}
else
{
// put all controller events into their own mode's mappings
for (const auto& item : DefaultRightJoystickMapping)
for(const auto& item : DefaultRightJoystickMapping)
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
for (const auto& item : DefaultRightKeyboardMapping)
for(const auto& item : DefaultRightKeyboardMapping)
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
for (const auto& item : DefaultRightDrivingMapping)
for(const auto& item : DefaultRightDrivingMapping)
setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults);
}
#if defined(RETRON77)
#if defined(RETRON77)
constexpr bool retron77 = true;
#else
#else
constexpr bool retron77 = false;
#endif
#endif
// Regular joysticks can only be used by one player at a time,
// so we need to separate the paddles onto different
@ -407,16 +418,16 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
// and 2600-daptors support two players natively.
const int paddlesPerJoystick = (j->type == PhysicalJoystick::Type::REGULAR && !retron77) ? 1 : 2;
if( paddlesPerJoystick == 2 )
if(paddlesPerJoystick == 2)
{
if( useLeftMappings )
if(useLeftMappings)
{
for (const auto& item : DefaultLeftPaddlesMapping)
for(const auto& item : DefaultLeftPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
else
{
for (const auto& item : DefaultRightPaddlesMapping)
for(const auto& item : DefaultRightPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
}
@ -433,29 +444,29 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
const bool useLeftPaddleMappings = (stick % 4) < 2;
const bool useAPaddleMappings = (stick % 2) == 0;
if( useLeftPaddleMappings )
if(useLeftPaddleMappings)
{
if( useAPaddleMappings )
if(useAPaddleMappings)
{
for (const auto& item : DefaultLeftAPaddlesMapping)
for(const auto& item : DefaultLeftAPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
else
{
for (const auto& item : DefaultLeftBPaddlesMapping)
for(const auto& item : DefaultLeftBPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
}
else
{
if( useAPaddleMappings )
if(useAPaddleMappings)
{
for (const auto& item : DefaultRightAPaddlesMapping)
for(const auto& item : DefaultRightAPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
else
{
for (const auto& item : DefaultRightBPaddlesMapping)
for(const auto& item : DefaultRightBPaddlesMapping)
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
}
}
@ -469,7 +480,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
}
case EventMode::kMenuMode:
for (const auto& item : DefaultMenuMapping)
for(const auto& item : DefaultMenuMapping)
setDefaultAction(stick, item, event, EventMode::kMenuMode, updateDefaults);
break;
@ -488,45 +499,71 @@ void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mod
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::defineControllerMappings(const Controller::Type type, Controller::Jack port)
void PhysicalJoystickHandler::defineControllerMappings(
Controller::Type type, Controller::Jack port, const Properties& properties,
Controller::Type qtType1, Controller::Type qtType2)
{
// Determine controller events to use
if(type == Controller::Type::QuadTari)
{
if(port == Controller::Jack::Left)
{
myLeftMode = getMode(qtType1);
myLeft2ndMode = getMode(qtType2);
}
else
{
myRightMode = getMode(qtType1);
myRight2ndMode = getMode(qtType2);
}
}
else
{
const EventMode mode = getMode(type);
if(port == Controller::Jack::Left)
myLeftMode = mode;
else
myRightMode = mode;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalJoystickHandler::getMode(const Properties& properties,
PropType propType)
{
const string& propName = properties.get(propType);
if(!propName.empty())
return getMode(Controller::getType(propName));
return EventMode::kJoystickMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalJoystickHandler::getMode(Controller::Type type)
{
// determine controller events to use
switch(type)
{
case Controller::Type::Keyboard:
case Controller::Type::KidVid:
if(port == Controller::Jack::Left)
myLeftMode = EventMode::kKeyboardMode;
else
myRightMode = EventMode::kKeyboardMode;
break;
using enum Controller::Type;
case Keyboard:
case KidVid:
return EventMode::kKeyboardMode;
case Controller::Type::Paddles:
case Controller::Type::PaddlesIAxDr:
case Controller::Type::PaddlesIAxis:
if(port == Controller::Jack::Left)
myLeftMode = EventMode::kPaddlesMode;
else
myRightMode = EventMode::kPaddlesMode;
break;
case Paddles:
case PaddlesIAxDr:
case PaddlesIAxis:
return EventMode::kPaddlesMode;
case Controller::Type::CompuMate:
myLeftMode = myRightMode = EventMode::kCompuMateMode;
break;
case CompuMate:
return EventMode::kCompuMateMode;
case Controller::Type::Driving:
if(port == Controller::Jack::Left)
myLeftMode = EventMode::kDrivingMode;
else
myRightMode = EventMode::kDrivingMode;
break;
case Driving:
return EventMode::kDrivingMode;
default:
// let's use joystick then
if(port == Controller::Jack::Left)
myLeftMode = EventMode::kJoystickMode;
else
myRightMode = EventMode::kJoystickMode;
return EventMode::kJoystickMode;
}
}
@ -543,8 +580,38 @@ void PhysicalJoystickHandler::enableEmulationMappings()
enableCommonMappings();
// Process in increasing priority order, so that in case of mapping clashes
// the higher priority controller has preference
switch(myRight2ndMode)
{
case EventMode::kPaddlesMode:
enableMappings(QTPaddles4Events, EventMode::kPaddlesMode);
break;
case EventMode::kEmulationMode: // no QuadTari
break;
default:
enableMappings(QTJoystick4Events, EventMode::kJoystickMode);
break;
}
switch(myLeft2ndMode)
{
case EventMode::kPaddlesMode:
enableMappings(QTPaddles3Events, EventMode::kPaddlesMode);
break;
case EventMode::kEmulationMode: // no QuadTari
break;
default:
enableMappings(QTJoystick3Events, EventMode::kJoystickMode);
break;
}
// enable right mode first, so that in case of mapping clashes the left controller has preference
switch (myRightMode)
switch(myRightMode)
{
case EventMode::kPaddlesMode:
enableMappings(RightPaddlesEvents, EventMode::kPaddlesMode);
@ -563,7 +630,7 @@ void PhysicalJoystickHandler::enableEmulationMappings()
break;
}
switch (myLeftMode)
switch(myLeftMode)
{
case EventMode::kPaddlesMode:
enableMappings(LeftPaddlesEvents, EventMode::kPaddlesMode);
@ -588,7 +655,7 @@ void PhysicalJoystickHandler::enableCommonMappings()
{
for (int i = Event::NoType + 1; i < Event::LastType; i++)
{
const Event::Type event = static_cast<Event::Type>(i);
const auto event = static_cast<Event::Type>(i);
if(isCommonEvent(event))
enableMapping(event, EventMode::kCommonMode);
@ -603,14 +670,14 @@ void PhysicalJoystickHandler::enableMappings(const Event::EventSet& events, Even
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::enableMapping(const Event::Type event, EventMode mode)
void PhysicalJoystickHandler::enableMapping(Event::Type event, EventMode mode)
{
// copy from controller mode into emulation mode
for (auto& stick : mySticks)
{
const PhysicalJoystickPtr j = stick.second;
JoyMap::JoyMappingArray joyMappings = j->joyMap.getEventMapping(event, mode);
const JoyMap::JoyMappingArray joyMappings = j->joyMap.getEventMapping(event, mode);
for (const auto& mapping : joyMappings)
j->joyMap.add(event, EventMode::kEmulationMode, mapping.button,
@ -619,7 +686,7 @@ void PhysicalJoystickHandler::enableMapping(const Event::Type event, EventMode m
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const EventMode mode) const
EventMode PhysicalJoystickHandler::getEventMode(Event::Type event, EventMode mode)
{
if(mode == EventMode::kEmulationMode)
{
@ -643,37 +710,42 @@ EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const E
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isJoystickEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isJoystickEvent(Event::Type event)
{
return LeftJoystickEvents.find(event) != LeftJoystickEvents.end()
|| RightJoystickEvents.find(event) != RightJoystickEvents.end();
return LeftJoystickEvents.contains(event)
|| QTJoystick3Events.contains(event)
|| RightJoystickEvents.contains(event)
|| QTJoystick4Events.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isPaddleEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isPaddleEvent(Event::Type event)
{
return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end()
|| RightPaddlesEvents.find(event) != RightPaddlesEvents.end();
return LeftPaddlesEvents.contains(event)
|| QTPaddles3Events.contains(event)
|| RightPaddlesEvents.contains(event)
|| QTPaddles4Events.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isKeyboardEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isKeyboardEvent(Event::Type event)
{
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
return LeftKeyboardEvents.contains(event)
|| RightKeyboardEvents.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isDrivingEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isDrivingEvent(Event::Type event)
{
return LeftDrivingEvents.find(event) != LeftDrivingEvents.end()
|| RightDrivingEvents.find(event) != RightDrivingEvents.end();
return LeftDrivingEvents.contains(event)
|| RightDrivingEvents.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::isCommonEvent(const Event::Type event) const
bool PhysicalJoystickHandler::isCommonEvent(Event::Type event)
{
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event) || isDrivingEvent(event));
return !(isJoystickEvent(event) || isPaddleEvent(event)
|| isKeyboardEvent(event) || isDrivingEvent(event));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -715,7 +787,7 @@ void PhysicalJoystickHandler::saveMapping()
for(const auto& [_name, _info]: myDatabase)
{
json map = _info.joy ? _info.joy->getMap() : _info.mapping;
const json map = _info.joy ? _info.joy->getMap() : _info.mapping;
if (!map.is_null()) mapping.emplace_back(map);
}
@ -734,9 +806,9 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
if(_joyptr)
{
//Joystick mapping / labeling
if(_joyptr->joyMap.getEventMapping(event, evMode).size())
if(!_joyptr->joyMap.getEventMapping(event, evMode).empty())
{
if(buf.str() != "")
if(!buf.view().empty())
buf << ", ";
buf << _joyptr->joyMap.getEventMappingDesc(_id, event, evMode);
}
@ -746,8 +818,8 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, int stick,
int button, JoyAxis axis, JoyDir adir)
bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode,
int stick, int button, JoyAxis axis, JoyDir adir)
{
const PhysicalJoystickPtr j = joy(stick);
@ -787,8 +859,8 @@ bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, i
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick,
int button, int hat, JoyHatDir hdir)
bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode,
int stick, int button, int hat, JoyHatDir hdir)
{
const PhysicalJoystickPtr j = joy(stick);
@ -829,17 +901,18 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
if(j)
{
//int button = j->buttonLast[stick];
//int button = j->buttonLast;
switch(j->type)
{
using enum PhysicalJoystick::Type;
// Since the various controller classes deal with Stelladaptor
// devices differently, we send the raw X and Y axis data directly,
// and let the controller handle it
// These events don't have to pass through handleEvent, since
// they can never be remapped
case PhysicalJoystick::Type::LEFT_STELLADAPTOR:
case PhysicalJoystick::Type::LEFT_2600DAPTOR:
case LEFT_STELLADAPTOR:
case LEFT_2600DAPTOR:
if(myOSystem.hasConsole()
&& myOSystem.console().leftController().type() == Controller::Type::Driving)
{
@ -850,8 +923,8 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
handleRegularAxisEvent(j, stick, axis, value);
break; // axis on left controller (0)
case PhysicalJoystick::Type::RIGHT_STELLADAPTOR:
case PhysicalJoystick::Type::RIGHT_2600DAPTOR:
case RIGHT_STELLADAPTOR:
case RIGHT_2600DAPTOR:
if(myOSystem.hasConsole()
&& myOSystem.console().rightController().type() == Controller::Type::Driving)
{
@ -872,7 +945,7 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
void PhysicalJoystickHandler::handleRegularAxisEvent(const PhysicalJoystickPtr& j,
int stick, int axis, int value)
{
const int button = j->buttonLast[stick];
const int button = j->buttonLast;
if(myHandler.state() == EventHandlerState::EMULATION)
{
@ -952,7 +1025,7 @@ void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, bool pressed
if(j)
{
j->buttonLast[stick] = pressed ? button : JOY_CTRL_NONE;
j->buttonLast = pressed ? button : JOY_CTRL_NONE;
// Handle buttons which switch eventhandler state
if(!pressed && myHandler.changeStateByEvent(j->joyMap.get(EventMode::kEmulationMode, button)))
@ -979,7 +1052,7 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
if(j)
{
const int button = j->buttonLast[stick];
const int button = j->buttonLast;
if(myHandler.state() == EventHandlerState::EMULATION)
{
@ -1014,29 +1087,35 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VariantList PhysicalJoystickHandler::database() const
PhysicalJoystickHandler::MinStrickInfoList PhysicalJoystickHandler::minStickList() const
{
VariantList db;
for(const auto& [_name, _info]: myDatabase)
VarList::push_back(db, _name, _info.joy ? _info.joy->ID : -1);
MinStrickInfoList list;
return db;
for(const auto& [_name, _info] : myDatabase)
{
const MinStrickInfo stick(_name,
_info.joy ? _info.joy->ID : -1,
_info.joy ? _info.joy->port : PhysicalJoystick::Port::AUTO);
list.push_back(stick);
}
return list;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
{
os << "---------------------------------------------------------" << endl
<< "joy database:" << endl;
os << "---------------------------------------------------------\n"
<< "joy database:\n";
for(const auto& [_name, _info]: jh.myDatabase)
os << _name << endl << _info << endl << endl;
os << _name << '\n' << _info << "\n\n";
os << "---------------------" << endl
<< "joy active:" << endl;
os << "---------------------\n"
<< "joy active:\n";
for(const auto& [_id, _joyptr]: jh.mySticks)
os << _id << ": " << *_joyptr << endl;
os << _id << ": " << *_joyptr << '\n';
os << "---------------------------------------------------------"
<< endl << endl << endl;
<< "\n\n\n";
return os;
}
@ -1044,8 +1123,9 @@ ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDigitalDeadZone(int direction)
{
int deadZone = BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
const int deadZone =
BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
myOSystem.settings().setValue("joydeadzone", deadZone);
Controller::setDigitalDeadZone(deadZone);
@ -1053,15 +1133,17 @@ void PhysicalJoystickHandler::changeDigitalDeadZone(int direction)
ostringstream ss;
ss << std::round(Controller::digitalDeadZoneValue(deadZone) * 100.F / 32768) << "%";
myOSystem.frameBuffer().showGaugeMessage("Digital controller dead zone", ss. str(), deadZone,
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
myOSystem.frameBuffer().showGaugeMessage(
"Digital controller dead zone", ss.view(), deadZone,
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeAnalogPaddleDeadZone(int direction)
{
int deadZone = BSPF::clamp(myOSystem.settings().getInt("adeadzone") + direction,
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
const int deadZone =
BSPF::clamp(myOSystem.settings().getInt("adeadzone") + direction,
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
myOSystem.settings().setValue("adeadzone", deadZone);
Controller::setAnalogDeadZone(deadZone);
@ -1069,15 +1151,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleDeadZone(int direction)
ostringstream ss;
ss << std::round(Controller::analogDeadZoneValue(deadZone) * 100.F / 32768) << "%";
myOSystem.frameBuffer().showGaugeMessage("Analog controller dead zone", ss.str(), deadZone,
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
myOSystem.frameBuffer().showGaugeMessage(
"Analog controller dead zone", ss.view(), deadZone,
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
const int sense =
BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
myOSystem.settings().setValue("psense", sense);
Paddles::setAnalogSensitivity(sense);
@ -1085,15 +1169,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
ostringstream ss;
ss << std::round(Paddles::analogSensitivityValue(sense) * 100.F) << "%";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle sensitivity", ss.str(), sense,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
myOSystem.frameBuffer().showGaugeMessage(
"Analog paddle sensitivity", ss.view(), sense,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeAnalogPaddleLinearity(int direction)
{
int linear = BSPF::clamp(myOSystem.settings().getInt("plinear") + direction * 5,
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
const int linear =
BSPF::clamp(myOSystem.settings().getInt("plinear") + direction * 5,
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
myOSystem.settings().setValue("plinear", linear);
Paddles::setAnalogLinearity(linear);
@ -1104,15 +1190,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleLinearity(int direction)
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle linearity", ss.str(), linear,
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
myOSystem.frameBuffer().showGaugeMessage(
"Analog paddle linearity", ss.view(), linear,
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
{
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
const int dejitter =
BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.settings().setValue("dejitter.base", dejitter);
Paddles::setDejitterBase(dejitter);
@ -1123,16 +1211,17 @@ void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter averaging",
ss.str(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.frameBuffer().showGaugeMessage(
"Analog paddle dejitter averaging", ss.view(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
{
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
const int dejitter =
BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.settings().setValue("dejitter.diff", dejitter);
Paddles::setDejitterDiff(dejitter);
@ -1143,16 +1232,17 @@ void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter reaction",
ss.str(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.frameBuffer().showGaugeMessage(
"Analog paddle dejitter reaction", ss.view(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
const int sense =
BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
myOSystem.settings().setValue("dsense", sense);
Paddles::setDigitalSensitivity(sense);
@ -1163,16 +1253,17 @@ void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Digital sensitivity",
ss.str(), sense,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
myOSystem.frameBuffer().showGaugeMessage(
"Digital sensitivity", ss.view(), sense,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
const int sense =
BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
myOSystem.settings().setValue("msense", sense);
Controller::setMouseSensitivity(sense);
@ -1180,16 +1271,17 @@ void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Mouse paddle sensitivity",
ss.str(), sense,
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
myOSystem.frameBuffer().showGaugeMessage(
"Mouse paddle sensitivity", ss.view(), sense,
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
const int sense =
BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
myOSystem.settings().setValue("tsense", sense);
PointingDevice::setSensitivity(sense);
@ -1197,16 +1289,17 @@ void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Mouse trackball sensitivity",
ss.str(), sense,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
myOSystem.frameBuffer().showGaugeMessage(
"Mouse trackball sensitivity", ss.view(), sense,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
Driving::MIN_SENSE, Driving::MAX_SENSE);
const int sense =
BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
Driving::MIN_SENSE, Driving::MAX_SENSE);
myOSystem.settings().setValue("dcsense", sense);
Driving::setSensitivity(sense);
@ -1214,9 +1307,9 @@ void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Driving controller sensitivity",
ss.str(), sense,
Driving::MIN_SENSE, Driving::MAX_SENSE);
myOSystem.frameBuffer().showGaugeMessage(
"Driving controller sensitivity", ss.view(), sense,
Driving::MIN_SENSE, Driving::MAX_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1391,13 +1484,22 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight
PhysicalJoystickHandler::EventMappingArray
PhysicalJoystickHandler::DefaultCommonMapping = {
// valid for all joysticks
// Note: buttons 0..2 are used by controllers!
#if defined(RETRON77)
{Event::CmdMenuMode, 3}, // Note: buttons 0..2 are used by controllers!
{Event::ExitMode, 4},
{Event::OptionsMenuMode, 5},
{Event::RewindPause, 6},
{Event::ConsoleSelect, 7},
{Event::ConsoleReset, 8},
{Event::CmdMenuMode, 3}, // Button "Y" / "4"
{Event::ExitMode, 4}, // Left Shoulder Button
{Event::OptionsMenuMode, 5}, // Right Shoulder Button
{Event::RewindPause, 7}, // Right Trigger Button
{Event::ConsoleSelect, 8}, // Button "Select"
{Event::ConsoleReset, 9}, // Button "Start"
#else
{Event::ConsoleSelect, 8}, // Button "Select"
{Event::ConsoleReset, 9}, // Button "Start"
{Event::ConsoleColorToggle, 3}, // Button "Y" / "4"
{Event::ConsoleLeftDiffToggle, 4}, // Left Shoulder Button
{Event::ConsoleRightDiffToggle, 5}, // Right Shoulder Button
{Event::CmdMenuMode, 6}, // Left Trigger Button
{Event::OptionsMenuMode, 7}, // Right Trigger Button
#endif
};
@ -1416,7 +1518,9 @@ PhysicalJoystickHandler::DefaultMenuMapping = {
{Event::UINavNext, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
{Event::UITabNext, 0, JoyAxis::X, JoyDir::POS},
{Event::UIUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
{Event::UIOK, 0 , JoyAxis::Y, JoyDir::NEG},
{Event::UIDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
{Event::UICancel, 0 , JoyAxis::Y, JoyDir::POS},
{Event::UINavPrev, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
{Event::UINavNext, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -46,6 +46,18 @@ using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
*/
class PhysicalJoystickHandler
{
public:
struct MinStrickInfo
{
string name;
int ID;
PhysicalJoystick::Port port;
explicit MinStrickInfo(string_view _name, int _id, PhysicalJoystick::Port _port)
: name{_name}, ID{_id}, port{_port} {}
};
using MinStrickInfoList = std::vector<MinStrickInfo>;
private:
struct StickInfo
{
@ -54,13 +66,13 @@ class PhysicalJoystickHandler
// on the 'mapping' instance variable; there lay dragons ...
// https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays
explicit StickInfo(nlohmann::json map, PhysicalJoystickPtr stick = nullptr)
: mapping(map), joy{std::move(stick)} {}
: mapping(map), joy{std::move(stick)} {} // NOLINT
nlohmann::json mapping;
PhysicalJoystickPtr joy;
friend ostream& operator<<(ostream& os, const StickInfo& si) {
os << " joy: " << si.joy << endl << " map: " << si.mapping;
os << " joy: " << si.joy << "\n map: " << si.mapping;
return os;
}
};
@ -68,18 +80,22 @@ class PhysicalJoystickHandler
public:
PhysicalJoystickHandler(OSystem& system, EventHandler& handler, Event& event);
static nlohmann::json convertLegacyMapping(const string& mapping);
static nlohmann::json convertLegacyMapping(string_view mapping);
/** Return stick ID on success, -1 on failure. */
int add(const PhysicalJoystickPtr& stick);
bool remove(int id);
bool remove(const string& name);
bool mapStelladaptors(const string& saport, int ID = -1);
bool remove(string_view name);
void setPort(string_view name, PhysicalJoystick::Port port);
bool mapStelladaptors(string_view saport, int ID = -1);
bool hasStelladaptors() const;
void setDefaultMapping(Event::Type type, EventMode mode);
void setDefaultMapping(Event::Type event, EventMode mode);
/** define mappings for current controllers */
void defineControllerMappings(const Controller::Type type, Controller::Jack port);
void defineControllerMappings(Controller::Type type, Controller::Jack port,
const Properties& properties,
Controller::Type qtType1 = Controller::Type::Unknown,
Controller::Type qtType2 = Controller::Type::Unknown);
/** enable mappings for emulation mode */
void enableEmulationMappings();
@ -111,8 +127,8 @@ class PhysicalJoystickHandler
return j->joyMap.get(mode, button, hat, hatDir);
}
/** Returns a list of pairs consisting of joystick name and associated ID. */
VariantList database() const;
/** Returns a list containing minimal controller info (name, ID, port). */
MinStrickInfoList minStickList() const;
void changeDigitalDeadZone(int direction = +1);
void changeAnalogPaddleDeadZone(int direction = +1);
@ -126,12 +142,12 @@ class PhysicalJoystickHandler
void changeDrivingSensitivity(int direction = +1);
private:
using StickDatabase = std::map<string,StickInfo>;
using StickDatabase = std::map<string, StickInfo, std::less<>>;
using StickList = std::map<int, PhysicalJoystickPtr>;
OSystem& myOSystem;
EventHandler& myHandler;
Event& myEvent;
OSystem& myOSystem; // NOLINT: we want a reference here
EventHandler& myHandler; // NOLINT: we want a reference here
Event& myEvent; // NOLINT: we want a reference here
// Contains all joysticks that Stella knows about, indexed by name
StickDatabase myDatabase;
@ -141,7 +157,7 @@ class PhysicalJoystickHandler
// Get joystick corresponding to given id (or nullptr if it doesn't exist)
// Make this inline so it's as fast as possible
const PhysicalJoystickPtr joy(int id) const {
PhysicalJoystickPtr joy(int id) const {
const auto& i = mySticks.find(id);
return i != mySticks.cend() ? i->second : nullptr;
}
@ -150,13 +166,15 @@ class PhysicalJoystickHandler
void addToDatabase(const PhysicalJoystickPtr& stick);
// Set default mapping for given joystick when no mappings already exist
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode,
void setStickDefaultMapping(int stick, Event::Type event, EventMode mode,
bool updateDefaults = false);
friend ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh);
JoyDir convertAxisValue(int value) const {
return value == int(JoyDir::NONE) ? JoyDir::NONE : value > 0 ? JoyDir::POS : JoyDir::NEG;
static constexpr JoyDir convertAxisValue(int value) {
return value == static_cast<int>(JoyDir::NONE)
? JoyDir::NONE
: value > 0 ? JoyDir::POS : JoyDir::NEG;
}
// Handle regular axis events (besides special Stelladaptor handling)
@ -179,23 +197,31 @@ class PhysicalJoystickHandler
EventMode mode = EventMode::kEmulationMode,
bool updateDefaults = false);
/** return event mode for given property */
static EventMode getMode(const Properties& properties, PropType propType);
/** return event mode for given controller type */
static EventMode getMode(Controller::Type type);
/** returns the event's controller mode */
EventMode getEventMode(const Event::Type event, const EventMode mode) const;
static EventMode getEventMode(Event::Type event, EventMode mode);
/** Checks event type. */
bool isJoystickEvent(const Event::Type event) const;
bool isPaddleEvent(const Event::Type event) const;
bool isKeyboardEvent(const Event::Type event) const;
bool isDrivingEvent(const Event::Type event) const;
bool isCommonEvent(const Event::Type event) const;
static bool isJoystickEvent(Event::Type event);
static bool isPaddleEvent(Event::Type event);
static bool isKeyboardEvent(Event::Type event);
static bool isDrivingEvent(Event::Type event);
static bool isCommonEvent(Event::Type event);
void enableCommonMappings();
void enableMappings(const Event::EventSet& events, EventMode mode);
void enableMapping(const Event::Type event, EventMode mode);
void enableMapping(Event::Type event, EventMode mode);
private:
EventMode myLeftMode{EventMode::kEmulationMode};
EventMode myRightMode{EventMode::kEmulationMode};
// Additional modes for QuadTari controller
EventMode myLeft2ndMode{EventMode::kEmulationMode};
EventMode myRight2ndMode{EventMode::kEmulationMode};
// Controller menu and common emulation mappings
static EventMappingArray DefaultMenuMapping;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -44,7 +44,7 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
: myOSystem{system},
myHandler{handler}
{
Int32 version = myOSystem.settings().getInt("event_ver");
const Int32 version = myOSystem.settings().getInt("event_ver");
bool updateDefaults = false;
// Compare if event list version has changed so that key maps became invalid
@ -70,10 +70,28 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
#ifdef DEBUGGER_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kPromptMode, updateDefaults);
#endif
#ifdef DEBUG_BUILD
verifyDefaultMapping(DefaultCommonMapping, EventMode::kEmulationMode, "EmulationMode");
verifyDefaultMapping(DefaultMenuMapping, EventMode::kMenuMode, "MenuMode");
#endif
}
#ifdef DEBUG_BUILD
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMapping, EventMode mode)
void PhysicalKeyboardHandler::verifyDefaultMapping(
PhysicalKeyboardHandler::EventMappingArray mapping, EventMode mode, string_view name)
{
for(const auto& item1 : mapping)
for(const auto& item2 : mapping)
if(item1.event != item2.event && item1.key == item2.key && item1.mod == item2.mod)
cerr << "ERROR! Duplicate hotkey mapping found: " << name << ", "
<< myKeyMap.getDesc(KeyMap::Mapping(mode, item1.key, item1.mod)) << "\n";
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::loadSerializedMappings(
string_view serializedMapping, EventMode mode)
{
json mapping;
@ -145,7 +163,7 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event,
{
// if there is no existing mapping for the event and
// the default mapping for the event is unused, set default key for event
if (myKeyMap.getEventMapping(map.event, mode).size() == 0 &&
if (myKeyMap.getEventMapping(map.event, mode).empty() &&
!isMappingUsed(mode, map))
{
addMapping(map.event, mode, map.key, static_cast<StellaMod>(map.mod));
@ -217,68 +235,65 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::defineControllerMappings(
const Controller::Type type, Controller::Jack port, const Properties& properties)
Controller::Type type, Controller::Jack port, const Properties& properties,
Controller::Type qtType1, Controller::Type qtType2)
{
//const string& test = myOSystem.settings().getString("aq");
// determine controller events to use
switch(type)
// Determine controller events to use
if(type == Controller::Type::QuadTari)
{
case Controller::Type::QuadTari:
if(port == Controller::Jack::Left)
{
myLeftMode = getMode(properties, PropType::Controller_Left1);
myLeft2ndMode = getMode(properties, PropType::Controller_Left2);
}
else
{
myRightMode = getMode(properties, PropType::Controller_Right1);
myRight2ndMode = getMode(properties, PropType::Controller_Right2);
}
break;
default:
if(port == Controller::Jack::Left)
{
const EventMode mode = getMode(type);
if(port == Controller::Jack::Left)
myLeftMode = mode;
else
myRightMode = mode;
break;
myLeftMode = getMode(qtType1);
myLeft2ndMode = getMode(qtType2);
}
else
{
myRightMode = getMode(qtType1);
myRight2ndMode = getMode(qtType2);
}
}
else
{
const EventMode mode = getMode(type);
if(port == Controller::Jack::Left)
myLeftMode = mode;
else
myRightMode = mode;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalKeyboardHandler::getMode(const Properties& properties, const PropType propType)
EventMode PhysicalKeyboardHandler::getMode(const Properties& properties,
PropType propType)
{
const string& propName = properties.get(propType);
if(!propName.empty())
return getMode(Controller::getType(propName));
return getMode(Controller::Type::Joystick);
return EventMode::kJoystickMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalKeyboardHandler::getMode(const Controller::Type type)
EventMode PhysicalKeyboardHandler::getMode(Controller::Type type)
{
switch(type)
{
case Controller::Type::Keyboard:
case Controller::Type::KidVid:
using enum Controller::Type;
case Keyboard:
case KidVid:
return EventMode::kKeyboardMode;
case Controller::Type::Paddles:
case Controller::Type::PaddlesIAxDr:
case Controller::Type::PaddlesIAxis:
case Paddles:
case PaddlesIAxDr:
case PaddlesIAxis:
return EventMode::kPaddlesMode;
case Controller::Type::CompuMate:
case CompuMate:
return EventMode::kCompuMateMode;
case Controller::Type::Driving:
case Driving:
return EventMode::kDrivingMode;
default:
@ -377,7 +392,7 @@ void PhysicalKeyboardHandler::enableCommonMappings()
{
for (int i = Event::NoType + 1; i < Event::LastType; i++)
{
const Event::Type event = static_cast<Event::Type>(i);
const auto event = static_cast<Event::Type>(i);
if (isCommonEvent(event))
enableMapping(event, EventMode::kCommonMode);
@ -393,19 +408,17 @@ void PhysicalKeyboardHandler::enableMappings(const Event::EventSet& events,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::enableMapping(const Event::Type event,
EventMode mode)
void PhysicalKeyboardHandler::enableMapping(Event::Type event, EventMode mode)
{
// copy from controller mode into emulation mode
KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode);
const KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode);
for (const auto& mapping : mappings)
myKeyMap.add(event, EventMode::kEmulationMode, mapping.key, mapping.mod);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
const EventMode mode) const
EventMode PhysicalKeyboardHandler::getEventMode(Event::Type event, EventMode mode)
{
if (mode == EventMode::kEmulationMode)
{
@ -429,41 +442,42 @@ EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isJoystickEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isJoystickEvent(Event::Type event)
{
return LeftJoystickEvents.find(event) != LeftJoystickEvents.end()
|| QTJoystick3Events.find(event) != QTJoystick3Events.end()
|| RightJoystickEvents.find(event) != RightJoystickEvents.end()
|| QTJoystick4Events.find(event) != QTJoystick4Events.end();
return LeftJoystickEvents.contains(event)
|| QTJoystick3Events.contains(event)
|| RightJoystickEvents.contains(event)
|| QTJoystick4Events.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isPaddleEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isPaddleEvent(Event::Type event)
{
return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end()
|| QTPaddles3Events.find(event) != QTPaddles3Events.end()
|| RightPaddlesEvents.find(event) != RightPaddlesEvents.end()
|| QTPaddles4Events.find(event) != QTPaddles4Events.end();
return LeftPaddlesEvents.contains(event)
|| QTPaddles3Events.contains(event)
|| RightPaddlesEvents.contains(event)
|| QTPaddles4Events.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isDrivingEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isKeyboardEvent(Event::Type event)
{
return LeftDrivingEvents.find(event) != LeftDrivingEvents.end()
|| RightDrivingEvents.find(event) != RightDrivingEvents.end();
return LeftKeyboardEvents.contains(event)
|| RightKeyboardEvents.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isKeyboardEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isDrivingEvent(Event::Type event)
{
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
return LeftDrivingEvents.contains(event)
|| RightDrivingEvents.contains(event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::isCommonEvent(const Event::Type event) const
bool PhysicalKeyboardHandler::isCommonEvent(Event::Type event)
{
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event));
return !(isJoystickEvent(event) || isPaddleEvent(event)
|| isKeyboardEvent(event) || isDrivingEvent(event));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -599,7 +613,7 @@ void PhysicalKeyboardHandler::toggleModKeys(bool toggle)
ostringstream ss;
ss << "Modifier key combos ";
ss << (modCombo ? "enabled" : "disabled");
myOSystem.frameBuffer().showTextMessage(ss.str());
myOSystem.frameBuffer().showTextMessage(ss.view());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -626,6 +640,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
#endif
{ Event::OptionsMenuMode, KBDK_TAB },
{ Event::CmdMenuMode, KBDK_BACKSLASH },
{ Event::ToggleBezel, KBDK_B, KBDM_CTRL },
{ Event::TimeMachineMode, KBDK_T, KBDM_SHIFT },
{ Event::DebuggerMode, KBDK_GRAVE },
{ Event::PlusRomsSetupMode, KBDK_P, KBDM_SHIFT | KBDM_CTRL | MOD3 },
@ -644,7 +659,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
{ 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::ToggleCorrectAspectRatio, KBDK_C, KBDM_SHIFT | KBDM_CTRL },
{ Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3 },
{ Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3 },
{ Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL },
@ -662,6 +677,8 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
{ Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3 },
{ Event::PhosphorIncrease, KBDK_4, MOD3 },
{ Event::TogglePhosphor, KBDK_P, MOD3 },
//{ Event::PhosphorModeDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL | MOD3 },
{ Event::PhosphorModeIncrease, KBDK_P, KBDM_CTRL | MOD3 },
{ Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3 },
{ Event::ScanlinesIncrease, KBDK_5, MOD3 },
{ Event::PreviousScanlineMask, KBDK_6, KBDM_SHIFT | MOD3 },
@ -709,7 +726,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
{ Event::ToggleFrameStats, KBDK_L, MOD3 },
{ Event::ToggleTimeMachine, KBDK_T, MOD3 },
#ifdef PNG_SUPPORT
#ifdef IMAGE_SUPPORT
{ Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL },
{ Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL },
#endif
@ -836,6 +853,7 @@ PhysicalKeyboardHandler::DefaultMenuMapping = {
{Event::UITabPrev, KBDK_TAB, KBDM_SHIFT | KBDM_CTRL},
{Event::UITabNext, KBDK_TAB, KBDM_CTRL},
{Event::ToggleUIPalette, KBDK_T, MOD3},
{Event::ToggleFullScreen, KBDK_RETURN, MOD3},
#ifdef BSPF_MACOS
@ -962,11 +980,9 @@ PhysicalKeyboardHandler::FixedPromptMapping = {
{Event::UIDown, KBDK_DOWN, KBDM_SHIFT},
{Event::UILeft, KBDK_DOWN},
{Event::UIRight, KBDK_UP},
};
#endif // DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = {
{Event::LeftJoystickUp, KBDK_UP},

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -24,6 +24,7 @@ class OSystem;
class EventHandler;
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
#include "EventHandlerConstants.hxx"
#include "Props.hxx"
@ -46,13 +47,17 @@ class PhysicalKeyboardHandler
PhysicalKeyboardHandler(OSystem& system, EventHandler& handler);
void loadSerializedMappings(const string& serializedMappings, EventMode mode);
void loadSerializedMappings(string_view serializedMappings, EventMode mode);
void setDefaultMapping(Event::Type type, EventMode mode, bool updateDefaults = false);
void setDefaultMapping(Event::Type event, EventMode mode,
bool updateDefaults = false);
/** define mappings for current controllers */
void defineControllerMappings(const Controller::Type type, Controller::Jack port,
const Properties& properties);
void defineControllerMappings(Controller::Type type,
Controller::Jack port,
const Properties& properties,
Controller::Type qtType1 = Controller::Type::Unknown,
Controller::Type qtType2 = Controller::Type::Unknown);
/** enable mappings for emulation mode */
void enableEmulationMappings();
@ -73,6 +78,10 @@ class PhysicalKeyboardHandler
return myKeyMap.get(mode, key, mod);
}
bool checkEventForKey(EventMode mode, StellaKey key, StellaMod mod) const {
return myKeyMap.check(mode, key, mod);
}
#ifdef BSPF_UNIX
/** See comments on 'myAltKeyCounter' for more information. */
uInt8& altKeyCount() { return myAltKeyCounter; }
@ -100,23 +109,28 @@ class PhysicalKeyboardHandler
EventMode mode = EventMode::kEmulationMode, bool updateDefaults = false);
/** returns the event's controller mode */
EventMode getEventMode(const Event::Type event, const EventMode mode) const;
static EventMode getEventMode(Event::Type event, EventMode mode);
/** Checks event type. */
bool isJoystickEvent(const Event::Type event) const;
bool isPaddleEvent(const Event::Type event) const;
bool isKeyboardEvent(const Event::Type event) const;
bool isDrivingEvent(const Event::Type event) const;
bool isCommonEvent(const Event::Type event) const;
static bool isJoystickEvent(Event::Type event);
static bool isPaddleEvent(Event::Type event);
static bool isKeyboardEvent(Event::Type event);
static bool isDrivingEvent(Event::Type event);
static bool isCommonEvent(Event::Type event);
void enableCommonMappings();
void enableMappings(const Event::EventSet& events, EventMode mode);
void enableMapping(const Event::Type event, EventMode mode);
void enableMapping(Event::Type event, EventMode mode);
/** return event mode for given property */
EventMode getMode(const Properties& properties, const PropType propType);
static EventMode getMode(const Properties& properties, PropType propType);
/** return event mode for given controller type */
EventMode getMode(const Controller::Type type);
static EventMode getMode(Controller::Type type);
#ifdef DEBUG_BUILD
void verifyDefaultMapping(PhysicalKeyboardHandler::EventMappingArray mapping,
EventMode mode, string_view name);
#endif
private:
OSystem& myOSystem;

View File

@ -8,28 +8,23 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2025 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.
//============================================================================
#if defined(PNG_SUPPORT)
#ifdef IMAGE_SUPPORT
#include <cmath>
#include "bspf.hxx"
#include "OSystem.hxx"
#include "Console.hxx"
#include "FrameBuffer.hxx"
#include "FBSurface.hxx"
#include "Props.hxx"
#include "Settings.hxx"
#include "TIASurface.hxx"
#include "Version.hxx"
#include "PNGLibrary.hxx"
#include "Rect.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::PNGLibrary(OSystem& osystem)
@ -38,34 +33,35 @@ PNGLibrary::PNGLibrary(OSystem& osystem)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
void PNGLibrary::loadImage(const string& filename, FBSurface& surface,
VariantList& metaData)
{
png_structp png_ptr{nullptr};
png_infop info_ptr{nullptr};
png_uint_32 iwidth{0}, iheight{0};
int bit_depth{0}, color_type{0}, interlace_type{0};
bool hasAlpha = false;
const auto loadImageERROR = [&](const char* s) {
const auto loadImageERROR = [&](string_view s) {
if(png_ptr)
png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : nullptr, nullptr);
if(s)
throw runtime_error(s);
throw runtime_error(string{s});
};
std::ifstream in(filename, std::ios_base::binary);
if(!in.is_open())
loadImageERROR("No snapshot found");
loadImageERROR("No image found");
// Create the PNG loading context structure
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
png_user_error, png_user_warn);
if(png_ptr == nullptr)
loadImageERROR("Couldn't allocate memory for PNG file");
loadImageERROR("Couldn't allocate memory for PNG image");
// Allocate/initialize the memory for image information. REQUIRED.
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == nullptr)
loadImageERROR("Couldn't create image information for PNG file");
loadImageERROR("Couldn't create image information for PNG image");
// Set up the input control
png_set_read_fn(png_ptr, &in, png_read_data);
@ -82,18 +78,25 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
// byte into separate bytes (useful for paletted and grayscale images).
png_set_packing(png_ptr);
// Only normal RBG(A) images are supported (without the alpha channel)
// Alpha channel is supported
if(color_type == PNG_COLOR_TYPE_RGBA)
{
png_set_strip_alpha(png_ptr);
hasAlpha = true;
}
else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
// TODO: preserve alpha
png_set_gray_to_rgb(png_ptr);
}
else if(color_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_palette_to_rgb(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
hasAlpha = true;
}
else
png_set_palette_to_rgb(png_ptr);
}
else if(color_type != PNG_COLOR_TYPE_RGB)
{
@ -101,8 +104,8 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
}
// Create/initialize storage area for the current image
if(!allocateStorage(iwidth, iheight))
loadImageERROR("Not enough memory to read PNG file");
if(!allocateStorage(iwidth, iheight, hasAlpha))
loadImageERROR("Not enough memory to read PNG image");
// The PNG read function expects an array of rows, not a single 1-D array
for(uInt32 irow = 0, offset = 0; irow < ReadInfo.height; ++irow, offset += ReadInfo.pitch)
@ -114,8 +117,11 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
// We're finished reading
png_read_end(png_ptr, info_ptr);
// Read the meta data we got
readMetaData(png_ptr, info_ptr, metaData);
// Load image into the surface, setting the correct dimensions
loadImagetoSurface(surface);
loadImagetoSurface(surface, hasAlpha);
// Cleanup
if(png_ptr)
@ -123,7 +129,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
void PNGLibrary::saveImage(const string& filename, const VariantList& metaData)
{
std::ofstream out(filename, std::ios_base::binary);
if(!out.is_open())
@ -137,31 +143,31 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
fb.scaleX(rectUnscaled.w()), fb.scaleY(rectUnscaled.h())
);
const png_uint_32 width = rect.w(), height = rect.h();
const size_t width = rect.w(), height = rect.h();
// Get framebuffer pixel data (we get ABGR format)
vector<png_byte> buffer(width * height * 4);
fb.readPixels(buffer.data(), width*4, rect);
fb.readPixels(buffer.data(), width * 4, rect);
// Set up pointers into "buffer" byte array
vector<png_bytep> rows(height);
for(png_uint_32 k = 0; k < height; ++k)
rows[k] = buffer.data() + k*width*4;
for(size_t k = 0; k < height; ++k)
rows[k] = buffer.data() + k * width * 4;
// And save the image
saveImageToDisk(out, rows, width, height, comments);
saveImageToDisk(out, rows, width, height, metaData);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
const Common::Rect& rect, const VariantList& comments)
const Common::Rect& rect, const VariantList& metaData)
{
std::ofstream out(filename, std::ios_base::binary);
if(!out.is_open())
throw runtime_error("ERROR: Couldn't create snapshot file");
// Do we want the entire surface or just a section?
png_uint_32 width = rect.w(), height = rect.h();
size_t width = rect.w(), height = rect.h();
if(rect.empty())
{
width = surface.width();
@ -170,29 +176,28 @@ void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
// Get the surface pixel data (we get ABGR format)
vector<png_byte> buffer(width * height * 4);
surface.readPixels(buffer.data(), width, rect);
surface.readPixels(buffer.data(), static_cast<uInt32>(width), rect);
// Set up pointers into "buffer" byte array
vector<png_bytep> rows(height);
for(png_uint_32 k = 0; k < height; ++k)
rows[k] = buffer.data() + k*width*4;
for(size_t k = 0; k < height; ++k)
rows[k] = buffer.data() + k * width * 4;
// And save the image
saveImageToDisk(out, rows, width, height, comments);
saveImageToDisk(out, rows, width, height, metaData);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::saveImageToDisk(std::ofstream& out, const vector<png_bytep>& rows,
png_uint_32 width, png_uint_32 height, const VariantList& comments)
size_t width, size_t height, const VariantList& metaData)
{
png_structp png_ptr = nullptr;
png_infop info_ptr = nullptr;
png_structp png_ptr{nullptr};
png_infop info_ptr{nullptr};
const auto saveImageERROR = [&](const char* s) {
const auto saveImageERROR = [&](string_view s) {
if(png_ptr)
png_destroy_write_struct(&png_ptr, &info_ptr);
if(s)
throw runtime_error(s);
throw runtime_error(string{s});
};
// Create the PNG saving context structure
@ -210,12 +215,13 @@ void PNGLibrary::saveImageToDisk(std::ofstream& out, const vector<png_bytep>& ro
png_set_write_fn(png_ptr, &out, png_write_data, png_io_flush);
// Write PNG header info
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
png_set_IHDR(png_ptr, info_ptr,
static_cast<png_uint_32>(width), static_cast<png_uint_32>(height), 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
// Write comments
writeComments(png_ptr, info_ptr, comments);
// Write meta data
writeMetaData(png_ptr, info_ptr, metaData);
// Write the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
@ -267,7 +273,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
buf << "Enabling snapshots in " << interval << " second intervals";
interval *= static_cast<uInt32>(myOSystem.frameRate());
}
myOSystem.frameBuffer().showTextMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.view());
setContinuousSnapInterval(interval);
}
else
@ -276,7 +282,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
buf << "Disabling snapshots, generated "
<< (mySnapCounter / mySnapInterval)
<< " files";
myOSystem.frameBuffer().showTextMessage(buf.str());
myOSystem.frameBuffer().showTextMessage(buf.view());
setContinuousSnapInterval(0);
}
}
@ -296,9 +302,9 @@ void PNGLibrary::takeSnapshot(uInt32 number)
// Figure out the correct snapshot name
string filename;
string sspath = myOSystem.snapshotSaveDir().getPath() +
(myOSystem.settings().getString("snapname") != "int" ?
myOSystem.romFile().getNameWithExt("")
const string sspath = myOSystem.snapshotSaveDir().getPath() +
(myOSystem.settings().getString("snapname") != "int"
? myOSystem.romFile().getNameWithExt("")
: myOSystem.console().properties().get(PropType::Cart_Name));
// Check whether we want multiple snapshots created
@ -307,14 +313,14 @@ void PNGLibrary::takeSnapshot(uInt32 number)
ostringstream buf;
buf << sspath << "_" << std::hex << std::setw(8) << std::setfill('0')
<< number << ".png";
filename = buf.str();
filename = buf.view();
}
else if(!myOSystem.settings().getBool("sssingle"))
{
// Determine if the file already exists, checking each successive filename
// until one doesn't exist
filename = sspath + ".png";
FilesystemNode node(filename);
const FSNode node(filename);
if(node.exists())
{
ostringstream buf;
@ -322,28 +328,29 @@ void PNGLibrary::takeSnapshot(uInt32 number)
{
buf.str("");
buf << sspath << "_" << i << ".png";
FilesystemNode next(buf.str());
const FSNode next(buf.view());
if(!next.exists())
break;
}
filename = buf.str();
filename = buf.view();
}
}
else
filename = sspath + ".png";
// Some text fields to add to the PNG snapshot
VariantList comments;
VariantList metaData;
ostringstream version;
VarList::push_back(metaData, "Title", "Snapshot");
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
<< BSPF::ARCH << "]";
VarList::push_back(comments, "Software", version.str());
VarList::push_back(metaData, "Software", version.view());
const string& name = (myOSystem.settings().getString("snapname") == "int")
? myOSystem.console().properties().get(PropType::Cart_Name)
: myOSystem.romFile().getName();
VarList::push_back(comments, "ROM Name", name);
VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(PropType::Cart_MD5));
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
VarList::push_back(metaData, "ROM Name", name);
VarList::push_back(metaData, "ROM MD5", myOSystem.console().properties().get(PropType::Cart_MD5));
VarList::push_back(metaData, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
// Now create a PNG snapshot
string message = "Snapshot saved";
@ -352,8 +359,9 @@ void PNGLibrary::takeSnapshot(uInt32 number)
try
{
Common::Rect rect;
const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
myOSystem.png().saveImage(filename, surface, rect, comments);
const FBSurface& surface =
myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
PNGLibrary::saveImage(filename, surface, rect, metaData);
}
catch(const runtime_error& e)
{
@ -368,7 +376,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
try
{
myOSystem.png().saveImage(filename, comments);
PNGLibrary::saveImage(filename, metaData);
}
catch(const runtime_error& e)
{
@ -382,26 +390,26 @@ void PNGLibrary::takeSnapshot(uInt32 number)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
bool PNGLibrary::allocateStorage(size_t width, size_t height, bool hasAlpha)
{
// Create space for the entire image (3 bytes per pixel in RGB format)
const size_t req_buffer_size = w * h * 3;
if(req_buffer_size > ReadInfo.buffer.size())
ReadInfo.buffer.resize(req_buffer_size);
// Create space for the entire image (3(4) bytes per pixel in RGB(A) format)
const size_t req_buffer_size = width * height * (hasAlpha ? 4 : 3);
if(req_buffer_size > ReadInfo.buffer.capacity())
ReadInfo.buffer.resize(req_buffer_size * 1.5);
const size_t req_row_size = h;
if(req_row_size > ReadInfo.row_pointers.size())
ReadInfo.row_pointers.resize(req_row_size);
const size_t req_row_size = height;
if(req_row_size > ReadInfo.row_pointers.capacity())
ReadInfo.row_pointers.resize(req_row_size * 1.5);
ReadInfo.width = w;
ReadInfo.height = h;
ReadInfo.pitch = w * 3;
ReadInfo.width = static_cast<png_uint_32>(width);
ReadInfo.height = static_cast<png_uint_32>(height);
ReadInfo.pitch = static_cast<png_uint_32>(width * (hasAlpha ? 4 : 3));
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::loadImagetoSurface(FBSurface& surface)
void PNGLibrary::loadImagetoSurface(FBSurface& surface, bool hasAlpha)
{
// First determine if we need to resize the surface
const uInt32 iw = ReadInfo.width, ih = ReadInfo.height;
@ -414,7 +422,7 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface)
surface.setSrcSize(iw, ih);
// Convert RGB triples into pixels and store in the surface
uInt32 *s_buf, s_pitch;
uInt32 *s_buf{nullptr}, s_pitch{0};
surface.basePtr(s_buf, s_pitch);
const uInt8* i_buf = ReadInfo.buffer.data();
const uInt32 i_pitch = ReadInfo.pitch;
@ -424,58 +432,78 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface)
{
const uInt8* i_ptr = i_buf;
uInt32* s_ptr = s_buf;
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
if(hasAlpha)
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 4)
*s_ptr++ = fb.mapRGBA(*i_ptr, *(i_ptr+1), *(i_ptr+2), *(i_ptr+3));
else
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::writeComments(const png_structp png_ptr, png_infop info_ptr,
const VariantList& comments)
void PNGLibrary::writeMetaData(png_structp png_ptr, png_infop info_ptr,
const VariantList& metaData)
{
const uInt32 numComments = static_cast<uInt32>(comments.size());
if(numComments == 0)
const size_t numMetaData = metaData.size();
if(numMetaData == 0)
return;
vector<png_text> text_ptr(numComments);
for(uInt32 i = 0; i < numComments; ++i)
vector<png_text> text_ptr(numMetaData);
for(size_t i = 0; i < numMetaData; ++i)
{
text_ptr[i].key = const_cast<char*>(comments[i].first.c_str());
text_ptr[i].text = const_cast<char*>(comments[i].second.toCString());
text_ptr[i].key = const_cast<char*>(metaData[i].first.c_str());
text_ptr[i].text = const_cast<char*>(metaData[i].second.toCString());
text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
text_ptr[i].text_length = 0;
}
png_set_text(png_ptr, info_ptr, text_ptr.data(), numComments);
png_set_text(png_ptr, info_ptr, text_ptr.data(), static_cast<int>(numMetaData));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_read_data(const png_structp ctx, png_bytep area, png_size_t size)
void PNGLibrary::readMetaData(png_structp png_ptr, png_infop info_ptr,
VariantList& metaData)
{
png_textp text_ptr{nullptr};
int numMetaData{0};
png_get_text(png_ptr, info_ptr, &text_ptr, &numMetaData);
metaData.clear();
for(int i = 0; i < numMetaData; ++i)
{
VarList::push_back(metaData, text_ptr[i].key, text_ptr[i].text);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size)
{
(static_cast<std::ifstream*>(png_get_io_ptr(ctx)))->read(
reinterpret_cast<char *>(area), size);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_write_data(const png_structp ctx, png_bytep area, png_size_t size)
void PNGLibrary::png_write_data(png_structp ctx, png_bytep area, png_size_t size)
{
(static_cast<std::ofstream*>(png_get_io_ptr(ctx)))->write(
reinterpret_cast<const char *>(area), size);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_io_flush(const png_structp ctx)
void PNGLibrary::png_io_flush(png_structp ctx)
{
(static_cast<std::ofstream*>(png_get_io_ptr(ctx)))->flush();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_user_warn(const png_structp ctx, png_const_charp str)
void PNGLibrary::png_user_warn(png_structp ctx, png_const_charp str)
{
throw runtime_error(string("PNGLibrary warning: ") + str);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::png_user_error(const png_structp ctx, png_const_charp str)
void PNGLibrary::png_user_error(png_structp ctx, png_const_charp str)
{
throw runtime_error(string("PNGLibrary error: ") + str);
}
@ -483,4 +511,4 @@ void PNGLibrary::png_user_error(const png_structp ctx, png_const_charp str)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::ReadInfoType PNGLibrary::ReadInfo;
#endif // PNG_SUPPORT
#endif // IMAGE_SUPPORT

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