Compare commits

...
228 Commits
Author SHA1 Message Date
Autechre de4e56ecf2 Update CHANGES.md 2022-03-29 03:08:45 +02:00
github-actions dc2f6da813 Fetch translations from Crowdin 2022-03-28 00:10:25 +00:00
Autechre 06921aebed Update CHANGES.md 2022-03-27 18:10:02 +02:00
OsirizX 083914aa5c [PSL1GHT] Update Makefile.psl1ght 2022-03-27 18:03:45 +02:00
OsirizX 80b06c37fe [PSL1GHT] Add experimental PSMove support for ps3 2022-03-27 18:03:40 +02:00
OsirizX d7002641c3 [PSL1GHT] Add libco support for ps3 2022-03-27 18:03:35 +02:00
OsirizX 4d367a2b59 [PSL1GHT] Add RSX graphics support for ps3 2022-03-27 18:03:30 +02:00
Autechre 1250ecbc46 Update CHANGES.md 2022-03-27 05:45:01 +02:00
twinaphex da15bc2802 Fix C89_BUILD 2022-03-27 05:32:41 +02:00
strotlog 91bf7b553a (mmap) Handle disconnect bits on both sides of len 2022-03-27 04:36:03 +01:00
jSTE0 55b77cb663 gfx/rs90: Optimise layout of sdl_rs90_video
Move frequently accessed member variables to the beginning of the
structure to improve cache locality. Having menu_texture at the end of
the structure also saves one instruction in the hot path of
sdl_rs90_gfx_frame() (for the ARMv5TE Miyoo) as well as a few other
functions.
2022-03-27 04:35:36 +01:00
revvv 78e7d23c14 Fix USB gamepad support
1. get_axis() didn't use AXIS_NEG_GET() / AXIS_POS_GET()
2. packet_handler() needs byte shift
3. log messages need SWAP_IF_BIG()
2022-03-27 04:35:06 +01:00
revvv b6ae697fad Make find_connection_entry() more specific
Controllers with same VID/PID are distinguished by the device name.
1. The Wii U only sends a prefix of the device name.
2. The check preferred the device name over VID/PID which was not
   intended.

Example: The device name "USB Gamepad" is truncated to "USB" which
was mapped to "Generic SNES USB Controller", although VID/PID did not
match.
2022-03-27 04:35:06 +01:00
revvv 75f94950bf Use "Retrode" as device name
Otherwise autoconfig file can't be found on the Wii U:
VID/PID are not available, so it has to match with 'input_device' and I
don't want to add additional autoconfig files with different
'input_device' strings.
2022-03-27 04:35:06 +01:00
github-actions 8b6fe0a934 Fetch translations from Crowdin 2022-03-27 00:10:36 +00:00
Jamiras f63c11ebaf free audio voices properly 2022-03-26 07:58:31 +01:00
github-actions 08c1c05f82 Fetch translations from Crowdin 2022-03-26 00:10:27 +00:00
twinaphex 6d73de8fa7 (iOS) Update to new Development Team 2022-03-25 16:55:22 +01:00
twinaphex 03ce03eb81 Remove unused variable 2022-03-25 16:19:39 +01:00
twinaphex af0e49df57 Fix some warnings 2022-03-25 15:41:30 +01:00
github-actions d89ab49d32 Fetch translations from Crowdin 2022-03-25 00:09:50 +00:00
Autechre b2ef25e20f Update CHANGES.md 2022-03-24 13:47:20 +01:00
sonninnos 6fcf291df4 Fix analog stick not working with 'Unified Menu Controls' 2022-03-24 13:46:57 +01:00
Colin Kinloch 60fab1c4a1 (Wayland) Create wl_data_device only when wl_seat and wl_data_device_manager exist 2022-03-23 06:52:16 +01:00
github-actions 0f85bbf32d Fetch translations from Crowdin 2022-03-23 00:10:06 +00:00
Gabriel Morazán 59b79e2191 Bump up version number (UWP msvc2019) 2022-03-22 21:40:24 +01:00
Gabriel Morazán eaf2f618b5 Bump up version number (UWP msvc2017) 2022-03-22 21:40:24 +01:00
twinaphex f3ce04be0c Bump up version + CHANGELOG 2022-03-22 21:01:06 +01:00
revvv b98b9471d9 Refactored to use new multi_pad interface 2022-03-22 18:17:50 +01:00
revvv 9b00a932d5 Remove special treatment for Retrode gamepad adapter 2022-03-22 18:17:50 +01:00
DisasterMo 2f88edb93f Add 6x10 font compatibility
This adds compatibility with 6x10 fonts. The hope is to be able to add more fonts to RGUI, like Latin Supplement Extended and others, in the future.
2022-03-22 18:14:46 +01:00
sonninnos 8fc14354e9 (RGUI) Add 'Gray Dark + Light' themes 2022-03-22 17:27:54 +01:00
sonninnos d7983f2827 (GLUI) Divider addition fix 2022-03-22 15:24:31 +01:00
sonninnos 8e962e495c (GLUI) Add 'Gray Dark + Light' themes 2022-03-22 13:09:48 +01:00
DisasterMo 1aa542be2d Fix messed up Crowdin config and restore synchronization 2022-03-22 06:59:12 +01:00
sonninnos fb444f9d91 (Ozone) Add 'Gray Dark + Light' themes 2022-03-22 06:59:05 +01:00
Colin Kinloch d95bc2dd54 (Wayland) Dynamically load libdecor at runtime 2022-03-22 06:58:41 +01:00
jdgleaver 1e31a8d5fd Remove 'Advanced Settings' flag from 'Settings > Core' menu 2022-03-21 15:10:31 +01:00
jdgleaver 2feca8994d Revert "(config_file) Prevent hash map corruption when calling config_unset()"
This reverts commit e5df8f7850.
2022-03-21 15:08:02 +01:00
jdgleaver 28247ba65d (config_file) Prevent hash map corruption when calling config_unset()
- This is a workaround for the broken 'RHMAP_DEL_STR()' implementation in rhmap.h
- This commit should be reverted when rhmap.h is fixed
2022-03-21 15:08:02 +01:00
jdgleaver 05b7ac47c3 Add 'Reset Input Mapping' option to 'Manage Remap Files' menu 2022-03-21 15:08:02 +01:00
Bernhard Schelling 780fdf721e Fix possible hash map corruption when deleting string keys 2022-03-21 15:07:53 +01:00
Colin Kinloch 47c850c7fd (Wayland) Dedupe VK/GL code 2022-03-21 07:50:34 +01:00
Colin Kinloch c6892d03c3 (Wayland) Fix splash screen when using xdg_toplevel 2022-03-20 20:18:11 +01:00
Colin Kinloch 82c69995f0 (Wayland) SHM anti-collision for the splash screen 2022-03-20 18:31:30 +01:00
Jamiras 4d2adee166 use display name for UI 2022-03-20 18:31:07 +01:00
Jamiras a18e29cc8a update to rcheevos 10.3.3 2022-03-20 18:31:07 +01:00
Colin Kinloch 065fb5acee (Wayland) Skip splash screen if window is not ready 2022-03-18 16:29:49 +01:00
sonninnos 27a6210f96 (XMB) Add title margin adjustment 2022-03-18 13:24:50 +01:00
jdgleaver c6e83d23f5 RETRO_ENVIRONMENT_SHUTDOWN Fixes
- Ensure core is properly unloaded when RETRO_ENVIRONMENT_SHUTDOWN is called
- Ensure menu stack is properly flushed when RETRO_ENVIRONMENT_SHUTDOWN is called
2022-03-18 13:15:47 +01:00
sonninnos 72513e29b2 Fix keyboard device remap nulling 2022-03-18 00:30:59 +01:00
github-actions 6d67c16507 Fetch translations from Crowdin 2022-03-17 00:08:48 +00:00
Mats 910a652b3c (steam) Replace OSK with the Steam one on the deck 2022-03-16 19:00:16 +01:00
jdgleaver ea77410037 Add 'Manage Remap Files' submenu + automatically save input remaps when closing content 2022-03-16 18:59:49 +01:00
Vladimir Serbinenko 96ddb301b6 Fix x1 name in emscripten 2022-03-16 18:08:20 +01:00
Francisco Javier Trujillo Mata fc653fad90 Add explicitly the supported menu drivers in PS2 2022-03-16 18:03:35 +01:00
Francisco Javier Trujillo Mata db74d7c81b Revert "Fix typo in Makefile.common when comparing for HAVE_MATERIALUI, HAVE_XMB and HAVE_OZONE"
This reverts commit 6f687fbb6c.
2022-03-16 18:03:35 +01:00
github-actions 675fe72ef0 Fetch translations from Crowdin 2022-03-16 00:08:44 +00:00
Francisco Javier Trujillo Mata e70b3d49b7 Fix typo in Makefie.ps2 2022-03-16 00:07:04 +01:00
Francisco Javier Trujillo Mata a404689894 Fix typo in Makefile.common when comparing for HAVE_MATERIALUI, HAVE_XMB and HAVE_OZONE 2022-03-16 00:07:04 +01:00
sonninnos 646b0f7209 (XMB+Ozone) Fix input icons 2022-03-15 22:34:15 +01:00
twinaphex 5253e4be23 Revert retroarch.cfg (regression introduced here - https://github.com/MajorPainTheCactus/RetroArch/commit/8fd35dae2d66ebe3fb4f04930ded2074e528ed 2022-03-15 17:41:23 +01:00
Vladimir Serbinenko 4d2178fafc Add missing emscripten cores 2022-03-15 17:44:00 +01:00
revvv 492a83e6d5 Wii: Fix find_connection_entry(): needs unsigned int
Otherwise the USB gamepad cannot be found, if VID/PID has leading zero.
For example: Retrode gamepad adapter:
             vid=1027 (0x403) pid=38849      (0x97c1) becomes
             vid=1027 (0x403) pid=-26687 (0xffff97c1)
2022-03-15 17:43:46 +01:00
jdgleaver b08314cf60 Prevent 'global' configuration of input libretro device type 2022-03-15 17:43:28 +01:00
TheRetroPirate 28145abde9 forgot to include the changes for the c_converter to include the metadata in the rdb files 2022-03-15 05:51:20 +01:00
TheRetroPirate 6f90b24f72 added more categories to the explore menu 2022-03-15 05:51:20 +01:00
Giovanni Cascione fe943a65e8 mali_fbdev: fix segfault switching video threaded from quickmenu 2022-03-15 05:45:38 +01:00
MajorPainTheCactus 3a25e1fbc3 Fixed D3D11 HDR bug just introduced 2022-03-15 05:44:07 +01:00
MajorPainTheCactus f3bda542d6 Fixed crash when using stock shader and HDR and previous optimisation 2022-03-15 05:44:07 +01:00
MajorPainTheCactus 32b8560858 Removed redundant copy of buffer in HDR mode if the shader has already a HDR format i.e R10G10B10A2 2022-03-15 05:44:07 +01:00
Colin Kinloch 86ca2006ea (Wayland) Fallback to shm_open when memfd_create fails (#13740) 2022-03-14 19:20:29 +01:00
jdgleaver 284fb6baa4 (menu_cbs_deferred_push.c) Minor clean-up of general_push() (#13742) 2022-03-14 18:18:07 +01:00
jdgleaver 1490ad18a2 Prevent log spam when using rewind hotkey with cores that don't support rewind if rewind functionality itself is disabled (#13741) 2022-03-14 18:17:43 +01:00
twinaphex 596bc4e686 (Steam) Swap OK/Cancel buttons by default 2022-03-14 18:12:25 +01:00
Mats d675276e28 (steam) Thread safety and style fixes (#13739) 2022-03-13 18:14:20 +01:00
Tony c1216fd16d (XMB) Vertical Fade corrections (#13736) 2022-03-12 16:50:56 +01:00
Nikos Chantziaras d9bc8fb796 Ozone: Add thumbnail scale option (#13620)
* Ozone: Add thumbnail scale option

* CHANGES.md: Add ozone thumbnail bar scaling option
2022-03-11 15:51:41 +01:00
Jamiras b4d9d6c5fc move slowdown disable into toggle_hardcore_active (#13734) 2022-03-11 07:17:54 +01:00
Nikos Chantziaras b094c58081 Add hotkey for toggling sync to exact content framerate (#13725)
* Add hotkey for toggling sync to exact content framerate

* CHANGES.md: add sync to exact content framerate toggle hotkey
2022-03-10 17:21:08 +01:00
jdgleaver 53bd6908e1 UWP build fix (#13726) 2022-03-10 15:15:45 +01:00
github-actions 0ecaa609f9 Fetch translations from Crowdin 2022-03-10 00:09:57 +00:00
jSTE0 715c054de5 Improve CPU architecture and model name identification for Miyoo (#13704)
* features_cpu: Return model name on non-x86 Linux platforms

Extract model name from /proc/cpuinfo.

* platform/unix: Rework identification of classic Arm CPUs

Identify pre-ARMv7 CPUs based on the machine hardware name starting with
"arm" instead of matching every individual variant. This will then
include the ARM926EJ-S which has armv5tejl as its machine hardware name.
2022-03-09 21:27:12 +01:00
jdgleaver c67806dbd7 Enable manual selection of which cores are displayed in the 'Standalone Cores' menu (#13722) 2022-03-09 17:49:16 +01:00
Colin Kinloch 3b08d63b23 (Wayland) Initial drag and drop (wl_data_offer) support (#13515) 2022-03-09 16:34:47 +01:00
Philippe Simons 8a8c2da042 emscripten: add jumpnbump core (#13720) 2022-03-09 15:31:31 +01:00
Mats 249241d7cd (steam) Initial integration with Steam API w/ mist (#13710) 2022-03-09 15:05:07 +01:00
Tony de22e06862 Reorder items in 'Core' menu (#13697) 2022-03-09 14:14:37 +01:00
Jamiras 4f62612044 replace real file system function with virtual wrapper call (#13717) 2022-03-09 08:20:58 +01:00
MrHuu 9ed51bc528 (3DS) Add new3ds speedup toggle (#13718) 2022-03-09 08:20:15 +01:00
github-actions b1f52a25ea Fetch translations from Crowdin 2022-03-09 00:08:58 +00:00
Autechre 32594e6643 Revert "(.gitlab-ci.yml) Temporarily disable build-retroarch-osx-ppc target while macosx-legacy runner is offline (#13685)" (#13716)
This reverts commit b74b2f9b87.
2022-03-08 15:19:37 +01:00
vaguerant 1726d8acb9 Add Optimize for GamePad option on Wii U (#13257)
* Add 'Optimize for Wii U GamePad' option

* style nit
2022-03-08 14:56:51 +01:00
twinaphex 9bcee062ff Cleanups/warnings 2022-03-07 19:32:01 +01:00
Autechre df553bb7f5 Update CHANGES.md 2022-03-07 19:12:23 +01:00
Michael Burgardt 56f2e2f7b8 Add Czech language option (#13680) 2022-03-07 19:11:39 +01:00
yoshisugaandgithub-actions 01cb10d8b3 [iOS 13+] Support a toolbar that allows toggling of onscreen keyboard and touch mouse (#13700)
* Fetch translations from Crowdin

* Support for showing and hiding indicator and navigation bar

* Refactored to use a view model

* Support defining helper bar items and support showing/hiding keyboard

* reorganized source files into separate logical files

* Moved mouse support to swift (except for delegate implementation), added support for enabling touch mouse in helper bar; reorganized swift source files

* Reorganized keyboard files; added the touch mouse messages to the RA localization files; use the RA notification system

* change keyboard letters to uppercase for clarity

Co-authored-by: github-actions <[email protected]>
2022-03-07 19:09:49 +01:00
twinaphex 4d112da58d Silence some MSVC code analysis warnings 2022-03-07 19:02:46 +01:00
Vladimir Serbinenko c11a798467 Series of djgpp fixes (#13705)
* features_cpu: Fix clock for djgpp

* frontend_dos_set_fork: Fix wrong id names

* dos_input: Fix missing indexing

* dos_joypad: Fix wrong id name

* Fix menu drawing

Menu is already prescaled to VGA_WIDTH x VGA_HEIGHT in vga_menu_frame. We need
to always use those dimensions

* Change dos compilation from griffin to common

* Set vga menu size to 320x200

* Add DOS compilation in gitlab-ci.yml
2022-03-05 15:53:18 +01:00
twinaphex 460f5e745d Silence some MSVC 2019 code analysis warnings 2022-03-05 14:39:56 +01:00
Keith Bowes 97c5c269a7 Added Changelog for RetroArch 1.10.1 (#13702) 2022-03-04 17:36:42 +01:00
Vladimir Serbinenko 4a53c6771c Several fixes and improvements do NGC and Wii (#13698)
* Support new elf2dol path in Makefile.griffin

* Fix NULL pointer dereference when no core info is available

* Fix double include of different versions of libogc

* Move ngc and wii to Makefile.common

Resulting binary is 60K *smaller*. This is surprising but probably due to
less inlining happening

* gx_gfx: Fix hang on gfx initialization

* Remove sthread_isself on NGC/Wii

It relies on pthread_equal that is not there for either legacy pthreads
or normal pthreads on those platforms

* Wii networking

* Missing includes in split

* Network fixes

* Fix logging of non-format string as a format

* Support for gx netlogger

* Network fix

* Network fixes

* Network info

* gx: Move config files to app directory

Otherwise it clashes between wiiU and vWii version with unpredictable
effects
2022-03-04 13:43:00 +01:00
Gabriel Morazán 35312feab6 Bump version number for UWP Build files. (#13695)
* Bump version number (msvc2019-UWP)

* Bump version number (msvc2017-UWP)
2022-03-03 15:39:51 +01:00
twinaphex 621f51394b Bump version 2022-03-03 14:28:38 +01:00
jSTE0 4896832612 platform/miyoo: Enable NEAREST audio resampler (#13694)
This platform actually defaults to the NEAREST audio resampler.
2022-03-03 12:56:39 +01:00
jdgleaver 3e4201ed30 Bitmap font improvements (#13693) 2022-03-02 16:47:46 +01:00
jdgleaver 4c87c307cc Disable per-game and per-content-directory remaps when running contentless cores (#13687) 2022-03-01 09:45:17 +01:00
Tony e8e8404741 (WinRaw) Enable mouse overlay control (#13688) 2022-03-01 09:45:07 +01:00
jdgleaver f6dc1c6d93 Disable per-game and per-content-directory shader presets when running contentless cores (#13690) 2022-03-01 09:44:55 +01:00
jdgleaver b74b2f9b87 (.gitlab-ci.yml) Temporarily disable build-retroarch-osx-ppc target while macosx-legacy runner is offline (#13685) 2022-02-28 13:57:16 +01:00
jdgleaver 0f2cb88ec6 Enable config overrides for contentless cores (#13684) 2022-02-28 13:45:51 +01:00
Tony 69cf8b1795 Fix some command line segfaults (#13682) 2022-02-28 10:32:50 +01:00
Tony cfd408db86 Show core version in 'Core Information' (#13677) 2022-02-27 05:30:12 +01:00
Tony 3b1d75d9cf Console help output cleanup (#13678) 2022-02-27 05:30:04 +01:00
yoshisugaandgithub-actions ba0d42ceb3 [iOS] Fix RetroArch_iOS9 project (#13679)
* Fetch translations from Crowdin

* Fix iOS 9 xcode project to include the JITSupport files

Co-authored-by: github-actions <[email protected]>
2022-02-27 05:18:25 +01:00
github-actions 6faf2fe5b9 Fetch translations from Crowdin 2022-02-27 00:10:40 +00:00
Guo Yunhe ab65e31e09 fix: osd fonts for chinese, korean, arabic and persian (#13639) 2022-02-26 18:05:55 +01:00
Gabriel Morazán 79e4106cc8 (Xbox/UWP) A small oversight from PR #13669. (#13674)
* Forgot to add the flags there, oops. (msvc2017)

* Forgot to add the flags there too, oops. (msvc2019)
2022-02-26 17:57:29 +01:00
Braden Farmer e215f56490 Android: Add HAVE_LANGEXTRA back to makefile (#13676)
Fixes #13672
2022-02-26 17:56:38 +01:00
github-actions 2c65382d50 Fetch translations from Crowdin 2022-02-26 00:09:11 +00:00
jdgleaver 8739264485 Enable runtime logging for contentless cores (#13671) 2022-02-25 18:23:55 +01:00
Jamiras e4d62a3b9f apply disconnect logic for command_memory_read/write (#13668) 2022-02-25 18:23:38 +01:00
Gabriel Morazán e137f2c9dc (Xbox/UWP) Fix CHD not working with Cheevos / Add 7zip support. (#13669)
* Add HAVE_CHD and HAVE_7ZIP to UWP (msvc2017)

* Add HAVE_CHD and HAVE_7ZIP to UWP (msvc2019)

* Add _7ZIP_ST to UWP (msvc2017)

* Add _7ZIP_ST to UWP (msvc2019)
2022-02-25 18:23:29 +01:00
github-actions 8f82bcaad9 Fetch translations from Crowdin 2022-02-25 00:09:27 +00:00
TheRhysWyrill bc756e31d9 Updated Xbox/UWP Icon and Splash Screen (#13651)
* Asset Optimization

* Asset Optimization

* New Xbox/UWP Icon and Splash Screen

Replaced the Icon and Splash Screen for the Xbox/UWP port of RetroArch with a more subtle design.

* Updated Xbox/UWP Icon and Splash Screen

Updated the Icon and Splash Screen for the Xbox/UWP port of RetroArch with a more subtle design.

* Updated Xbox/UWP Icon and Splash Screen

Updated the Icon and Splash Screen for the Xbox/UWP port of RetroArch with a more subtle design.
2022-02-24 23:50:19 +01:00
Tony 977a7d3eb6 Volume hotkey logic+response improvement (#13667) 2022-02-24 23:09:17 +01:00
jdgleaver b697f556e5 Ensure that cores are deinitialised correctly following initialisation failure (#13665) 2022-02-24 14:49:33 +01:00
Tony f0d9add1b2 (DInput/WinRaw) Ignore 'unknown/undefined' key (#13660) 2022-02-24 07:10:47 +01:00
Tony 7768c296b9 Prevent refresh rate switching to half frame rate modes (#13656) 2022-02-24 07:10:27 +01:00
github-actions 569704fb37 Fetch translations from Crowdin 2022-02-24 00:09:21 +00:00
jdgleaver ee4486068d (XMB+Ozone) Improve efficiency/accuracy of History/Favorites icon rendering (#13661) 2022-02-23 16:53:24 +01:00
github-actions 3d08aa8e32 Fetch translations from Crowdin 2022-02-23 00:09:57 +00:00
jdgleaver 9b0cb0fc92 Add 'Standalone Cores' menu (#13655) 2022-02-22 19:23:48 +01:00
Colin Kinloch 6dec52fda7 (Wayland) Fix wayland vulkan not reacting to initial resize (#13640)
(Wayland) Correct log stamps for GL or Vulkan

(Wayland) Fix style issues and sync formatting on identical code in GL and Vulkan
2022-02-22 08:58:46 +01:00
Cthulhu-throwaway 023f427856 [UPnP] Stability fixes (#13652) 2022-02-22 08:22:10 +01:00
yoshisuga bc02f8319e [iOS] New iOS 13 project to support Swift; Custom keyboard and touch mouse support (#13435)
* Support for Swift, added emulator keyboard

* fixed toggle key handling using magic number hack for now

* fixed keyboard transparency slider for now with suboptimal fix; add gesture recognizer to hide/show keyboard

* Support CocoaView extensions in Swift; move keyboard delegate impl and setup to swift extension

* moved keyboard view model creation out of EmulatorKeyboard

* implement key pressed delegate in swift extension

* added input method for directly sending RETROK_* codes to support a touchscreen keyboard; assign keyboard model delegates; updated keyboard layout (added F1-F12 keys); change shift, control and alt keys to be modifiers

* enable focus mode when custom keyboard is shown; enable/disable overlay when custom keyboard is toggled

* Specify -DHAVE_OPENGLES2 instead of -DHAVE_OPENGLES3 since glsym_es3.h does not compile in iOS 14.5
Fix tvOS build using compiler flags

* Create new project for iOS 13 deploy target; add check for deploy target to conditionally compile for new iOS 13 specific feature (custom keyboard)

* force disable core info caching for iOS, use opengl es2 for debug

* Add flag for iOS custom keyboard - 3-finger swipe up to show, 3-finger swipe down to hide

* use OpenGLES2 instead; using ES3 results in compile time errors on iOS 14.5

* code cleanup

* Updated references to -DDONT_WANT_ARM_ASM_OPTIMIZATIONS flag

* Add JIT support for non-jailbroken devices

* iOS: Add support for touch mouse handler

* Added a HAVE_IOS_TOUCHMOUSE preprocessor macro so that it builds under the iOS11_Metal xcode project

* Changed click-and-drag behavior to double tap hold and drag

* Visual improvements to the emulator keyboard: updated colors, improved key-press effect
2022-02-22 08:21:34 +01:00
github-actions 3d54d952a5 Fetch translations from Crowdin 2022-02-22 00:09:41 +00:00
Michael Burgardt 7df18ec59d Improve some texts (#13645) 2022-02-21 20:11:25 +01:00
github-actions 644e7dce7c Fetch translations from Crowdin 2022-02-21 00:09:21 +00:00
github-actions 3ae7d19cd5 Fetch translations from Crowdin 2022-02-20 00:10:13 +00:00
Autechre 78b25b20dd Revert "Update zlib.h (#13641)" (#13642)
This reverts commit 5a3cd8671e.
2022-02-19 21:56:52 +01:00
Philippe Simons 5a3cd8671e Update zlib.h (#13641)
fix compilation of uncompr.c
2022-02-19 21:11:59 +01:00
twinaphex d2ab5d05ee Remove GONG remnants 2022-02-19 05:33:32 +01:00
github-actions 8373ef1a61 Fetch translations from Crowdin 2022-02-19 00:09:36 +00:00
Colin Kinloch b2527b43e8 (Wayland) Show window early to get screen info (#13591)
* (Wayland) Show window early to get screen info

* Report current monitor size on initial get_video_size call

* Fullscreen to monitor selected in settings

* Fullscreen on current monitor when setting is set to automatic

* Fallback to shm_open when memfd_create is not supported
2022-02-18 19:59:41 +01:00
Keith BowesandMaxime Gauduin bbfcecfab0 Fix building against FFmpeg 5.0 (#13611)
Co-authored-by: Maxime Gauduin <[email protected]>
2022-02-18 18:40:54 +01:00
Rafael Toledo 03edf4f6a9 [Android] Include adaptative launcher icons (#13423) 2022-02-18 18:40:18 +01:00
Cthulhu-throwaway b0928cd0f8 [Netplay] Disable savestates on stateless mode (#13634)
Stateless mode is currently not working correctly and still using savestates.
2022-02-18 17:08:18 +01:00
Vladimir Serbinenko f0d8af0d34 Remove gong now that it has been successfully extracted into a standalone core (#13637) 2022-02-18 17:03:35 +01:00
github-actions 80e7e1983a Fetch translations from Crowdin 2022-02-18 00:08:46 +00:00
Mats e76da47b31 Fix base path when compiling with unix cwd (#13631) 2022-02-17 04:59:37 +01:00
github-actions 932c9b9926 Fetch translations from Crowdin 2022-02-17 00:07:37 +00:00
Jamiras c816cd2b61 change default for cheevos_richpresence_enable back to true (#13629) 2022-02-16 16:16:55 +01:00
MrHuu a7b7472c34 (RGUI) Add dynamic theme (#13612)
* (RGUI) Add dynamic theme

* (RGUI) Cleanup

* (RGUI) Apply jdgleaver's dynamic theme patch
2022-02-16 15:56:10 +01:00
github-actions 1fe70da946 Fetch translations from Crowdin 2022-02-16 00:07:48 +00:00
Braden Farmer 5bacf1e9be [Android] Populate external storage devices inside the file browser on Android 11+ devices (#13615)
[Android] Populate external storage devices inside the file browser on Android 11+ devices
2022-02-15 16:11:39 +01:00
Jamiras 5d3654ddbb (cheevos) support for identifying Dreamcast CHDs (#13628)
* support for identifying Dreamcast CHDs

* fix copy/paste error
2022-02-15 15:09:43 +01:00
github-actions 0e22b1ec73 Fetch translations from Crowdin 2022-02-15 00:08:15 +00:00
Michael Burgardt b8242601ec Fix localisations (#13622)
* Fix translations with messed-up string placement

* Fix Hebrew and Persian text display

Hebrew is now displayed properly as right-to-left.
Miscellaneous whitespaces, like the zero width non-joiner used in Persian, no longer break right-to-left texts.
2022-02-14 02:43:55 +01:00
github-actions 538b58aa7a Fetch translations from Crowdin 2022-02-14 00:07:43 +00:00
Jamiras 600a3365ea update to rcheevos 10.3.2 (#13621) 2022-02-13 21:40:16 +01:00
github-actions 19a1dbbc85 Fetch translations from Crowdin 2022-02-13 00:09:26 +00:00
github-actions 9ec7cecb93 Fetch translations from Crowdin 2022-02-12 00:07:40 +00:00
Salvador 8093f4595c Gba filter (#13613)
New GBA filter Upscale_240x160-320x240
2022-02-10 12:40:00 +01:00
Jamiras a576ee49db more description message for missing RetroAchievements credentials (#13617) 2022-02-09 17:18:03 +01:00
github-actions e71e895ad6 Fetch translations from Crowdin 2022-02-08 00:08:31 +00:00
TheRhysWyrill c97b40e900 Icon Optimization For Xbox/UWP Port (#13608)
* Asset Optimization

* Asset Optimization
2022-02-07 23:55:26 +01:00
jdgleaver ab8e8359a6 Fix segfault when launching content with cores that do not have serialized savestate support when rewind and cheevos hardcore mode are enabled (#13607) 2022-02-07 23:52:25 +01:00
github-actions 5d3ebd0ece Fetch translations from Crowdin 2022-02-07 00:07:46 +00:00
Michael Burgardt 504a6b9670 Fix Polish translation (#13601) 2022-02-06 04:40:08 +01:00
github-actions df1f7bffb9 Fetch translations from Crowdin 2022-02-06 00:09:13 +00:00
dbaronicaandDomagoj Baronica 2febc16e2e (UWP) - Implemented activation/starting of retroarch using URI activa… (#13563)
* (UWP) - Implemented activation/starting of retroarch using URI activation.

* Removed try-catch blocks, refactored argument parsing, ignore driver reset if content starting directly from arguments

Co-authored-by: Domagoj Baronica <[email protected]>
2022-02-05 12:46:42 +01:00
github-actions 5bc2d42cdc Fetch translations from Crowdin 2022-02-05 00:09:09 +00:00
jdgleaver 412c79862c (Qt) Fix crash when loading content via desktop menu while content is already running (#13595) 2022-02-05 00:26:10 +01:00
jdgleaver e541dd5ab1 Disable run-ahead and rewind based on save state support level defined in core info files (#13594)
* Disable run-ahead based on save state support level defined in core info files

* Disable rewind based on save state support level defined in core info files
2022-02-05 00:25:33 +01:00
Sou Bunnbu 763fcd8267 unix, win32: Allow set the default libretro_directory via environment variable (#12040) 2022-02-04 17:40:57 +01:00
github-actions d43b99cbac Fetch translations from Crowdin 2022-02-03 00:10:22 +00:00
TheRhysWyrill 37a91e1be5 Updated UWP Icons/Splash Screens (#13592)
* Updated UWP Icons

* Updated UWP Icons
2022-02-02 19:07:25 +01:00
jdgleaver 42e03cae83 Disable save states based on save state support level defined in core info files (#13562) 2022-02-02 16:49:53 +01:00
github-actions 6f7332c8fa Fetch translations from Crowdin 2022-02-02 00:09:36 +00:00
Vladimir Serbinenko 80cf91417c Enable 7zip on emscripten (#13533)
This makes it more in-line with other static platforms
2022-02-01 13:53:03 +01:00
Autechre b45a192416 Revert "(Wayland) Show window early to get screen info (#13582)" (#13590)
This reverts commit 4bb2c14293.
2022-02-01 12:47:53 +01:00
Colin Kinloch 4bb2c14293 (Wayland) Show window early to get screen info (#13582)
* Report current monitor size on initial get_video_size call

* Fullscreen to monitor selected in settings

* Fullscreen on current monitor when setting is set to automatic
2022-02-01 10:30:34 +01:00
Jahed 592f69ec69 MIYOO: Support battery level (#13585)
Currently when using RGUI on MiyooCFW (on a Powkiddy V90), despite enabling "Show Battery Level", nothing is shown. This change fixes that by comparing the correct voltage_now file.

There are no min/max files on the device so they're hardcoded similar to GMenu2X's indicator. Results are based on value distribution while running a game at max load.

GMenu2X battery level logic:
https://github.com/MiyooCFW/gmenunx/blob/7d51f8c22be22066fbaea671a4baf6d0d0ff5c3f/src/gmenu2x.cpp#L2587-L2598

Miyoo battery properties:
https://github.com/MiyooCFW/kernel/blob/f60025f03429ceb3771e5392a7d85c6f1780a42a/drivers/power/supply/miyoo-battery.c#L62-L72

RGUI battery level update:
https://www.libretro.com/index.php/retroarch-1-7-7-ui-updates/
2022-02-01 10:30:11 +01:00
Tony a106dedeb6 Fix default core on 'Add to Favorites' (#13587) 2022-02-01 10:29:56 +01:00
Jamiras cdc5e33953 support chd inside m3u (#13586) 2022-02-01 10:29:44 +01:00
github-actions f8c3c76e18 Fetch translations from Crowdin 2022-02-01 00:08:10 +00:00
Jamiras e301fffae3 prevent occasional infinite wait loading multi-disc game from secondary disc (#13561) 2022-01-31 19:28:31 +01:00
Tony 6d5d2e722d Logging cleanups (#13579) 2022-01-31 18:05:23 +01:00
Jamiras c092fa33e1 add mastery placard (#13575) 2022-01-31 16:33:23 +01:00
Víctor "IlDucci 900675ad23 [Typo fixing] Removing unneeded space before colons. (#13577) 2022-01-31 16:32:47 +01:00
jdgleaver a953b27614 Rework optional fast-forward frame skipping: Drop frames based on frame timing (#13578) 2022-01-31 16:32:17 +01:00
github-actions 6aa89b3723 Fetch translations from Crowdin 2022-01-31 00:07:42 +00:00
Vladimir Serbinenko 17ccfe4004 Support GL1 on osx-ppc (#13569)
* Fix handling of big-endianness in gl1

* Enable gl1 on osx-ppc

* Force gl1 on apple if gfx supports only gl1

* Backport gl2 apple workaround to gl1

* Fix big-endianness handling in widgets
2022-01-30 09:30:39 +01:00
Keith Bowes cce04bab70 Remove references to removed features (#13564) 2022-01-30 09:29:43 +01:00
Giovanni Cascione ffbbdbd256 fbdev: fix segfault on video thread switch and exit from hw_ctx cores (#13571) 2022-01-30 09:24:33 +01:00
github-actions 84052ee7e1 Fetch translations from Crowdin 2022-01-30 00:07:54 +00:00
Jamiras e1352060b5 stop load process if unable to retrieve achievement data (#13565) 2022-01-29 19:57:23 +01:00
Colin Kinloch a431760829 (Wayland) Release keys and mouse buttons on lost focus (#13567) 2022-01-29 19:57:06 +01:00
Colin Kinloch 5bd7433ac4 (Vulkan/GL) goto error without HAVE_EGL (#13568) 2022-01-29 19:56:49 +01:00
twinaphex 60eaf14afc C89_BUILDFIX 2022-01-29 10:55:31 +01:00
Dystopian 0afdb2a0cf Improve udev logging (#13549) 2022-01-29 10:57:38 +01:00
Tony 86cced8eab Fix frameskipping with duped frames (#13560) 2022-01-29 10:57:01 +01:00
github-actions dbe0252db4 Fetch translations from Crowdin 2022-01-29 00:07:53 +00:00
github-actions 4132176ece Fetch translations from Crowdin 2022-01-28 00:11:55 +00:00
Cthulhu-throwaway cd74221d33 [Networking] GetBestRoute refactor (#13553)
Refactor to support UWP.
2022-01-27 11:38:31 +01:00
Tony d9a4dc52c0 Increase maximum fast-forward ratio (#13552) 2022-01-27 11:37:09 +01:00
github-actions 8511152738 Fetch translations from Crowdin 2022-01-27 00:09:45 +00:00
Tony 84f558db0b Add optional frame skipping when fast-forwarding (#13550) 2022-01-26 18:30:33 +01:00
jdgleaver fa213a724f Fix crash when cores using RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK return false from retro_load_game() (#13547) 2022-01-26 18:30:07 +01:00
github-actions dfcbde86f7 Fetch translations from Crowdin 2022-01-26 00:09:04 +00:00
Jamiras 2ecb253ed4 (cheevos) upgrade to rcheevos 10.3 (#13546)
* upgrade to rcheevos 10.3

* use rcheevos cdreader for gdi/cue processing

* update widgets when loading state
2022-01-25 04:44:53 +01:00
Francisco Javier Trujillo Mata 3a67162ae2 Fix PS2 raboot name (#13543) 2022-01-25 04:19:18 +01:00
notaz 5f2ed6c85a VITA: don't fail if vm_memblock can't be allocated (#13545)
Failing here is catastrophic because we get no heap, the whole thing
just crashes and leaves nothing in the logs. vm_memblock is not even
used by RetroArch, it's just used by cores with dynarecs, so let the
cores themselves deal with problems if they arise.
2022-01-25 04:19:00 +01:00
Francisco Javier Trujillo Mata 86b47b4859 [PSP] Update Retroarch to latest PSPDev status (#13544)
* Added newlib changes

* Add action to launch PPSSPP simulator

* Remove legacy config for the stack and heap

* Add pthread

* Simplify kernel_functions and improve references to HAVE_KERNEL_PRX

* Add some flags

* Improve audio init/deinit

* Improve exit by clicking home

* Add CI for PSP1

* Update PSP.yml
2022-01-25 03:50:18 +01:00
github-actions 17362e3692 Fetch translations from Crowdin 2022-01-25 00:07:58 +00:00
jdgleaver 6ee3c14779 Add 'Core System Files Downloader' entry to the Online Updater (#13524) 2022-01-24 16:41:29 +01:00
Piotr Dobrowolski a612e7f7cc sdl_gl_ctx: fix focus detection on webOS (#13526) 2022-01-24 16:31:35 +01:00
Ryan Kuba 6ae1270e5c remove test for standard mapping in controller detection (#13528) 2022-01-24 16:31:03 +01:00
Vladimir Serbinenko 2c289a6212 Add FreeChaf to emscripten (#13529) 2022-01-24 16:30:35 +01:00
Keith Bowes 38e74ee3cf Restores mouse-grab toggling in Wayland. (#13537)
* Fixes mouse-grab toggling in Wayland.

Fixes #13536

* Indicate that input_wl_grab_mouse is a necessary function.

It might prevent it from being removed again in future cleanups.
2022-01-24 16:22:21 +01:00
Vladimir Serbinenko 4e24fb3d01 Add osx-ppc compilation for frontend (#13532)
* Fix old osx condition

Current code assumes that osx < 10.12 is equivalent to ppc osx. It's not
true as Leopard x86 is still < 10.12 but not ppc. As xcode compiles fat
binaries it includes osx x86 and compilation fails.

* Disable crtswitchres when no c++11 is available

Crtswitchres altually needs c++11. Since it's not that important to make
it compatible with lower c++, just disable if no c++11 is available

* Don't use firstObject on old Mac OS X.

It was introduced in 10.6, so on old ones just implement it ourselves

* Compile osx-ppc frontend

* osx-ppc: Build a fat binary

On 10.6 i386 xcode apparently refuses to build a pure ppc.
Settle for a fat binary.
2022-01-24 16:22:07 +01:00
github-actions 948ad76b14 Fetch translations from Crowdin 2022-01-24 00:07:57 +00:00
github-actions 245101b1a1 Fetch translations from Crowdin 2022-01-23 00:08:33 +00:00
github-actions e2848ad0d5 Fetch translations from Crowdin 2022-01-22 00:07:03 +00:00
twinaphex 688e00a25b Update CHANGES.md 2022-01-21 04:45:53 +01:00
Tony 49d3a947b8 (D3D10/11) Add vsync swap interval (#13521) 2022-01-21 04:35:22 +01:00
github-actions 5f6fc20360 Fetch translations from Crowdin 2022-01-21 00:10:19 +00:00
523 changed files with 48138 additions and 7634 deletions

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
name: CI PSP
on:
push:
pull_request:
repository_dispatch:
types: [run_build]
jobs:
build:
runs-on: ubuntu-latest
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-psp:latest
options: --user root
steps:
- uses: actions/checkout@v2
- name: Compile bootstrap
run: |
cd bootstrap/psp1/kernel_functions_prx
make -j$(getconf _NPROCESSORS_ONLN) clean
make -j$(getconf _NPROCESSORS_ONLN)
- name: Compile Salamander
run: |
make -f Makefile.psp1.salamander -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.psp1.salamander -j$(getconf _NPROCESSORS_ONLN)
- name: Compile RA
run: |
make -f Makefile.psp1 -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.psp1 -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v2
with:
name: RA-PSP-dummy-${{ steps.slug.outputs.sha8 }}
path: |
kernel_functions.prx
EBOOT.PBP
+40
View File
@@ -363,6 +363,29 @@ build-retroarch-osx-opengl-x64:
XCPROJECT_NAME: RetroArch
XCCONFIG: OpenGL_GitLabCI.xcconfig
build-retroarch-osx-ppc:
stage: build
artifacts:
paths:
- ${XCPROJECT_NAME}.zip
- retroarch-repo/
expire_in: 10 min
dependencies: []
variables:
XCPROJECT_NAME: RetroArch
XCCONFIG: OpenGL_GitLabCI.xcconfig
tags:
- macosx-legacy
script:
- xcodebuild -target RetroArch -configuration Release -project pkg/apple/RetroArch_PPC.xcodeproj ONLY_ACTIVE_ARCH=NO
- pushd pkg/apple/build/Release/
- ditto -c -k --sequesterRsrc --keepParent RetroArch.app ${XCPROJECT_NAME}.zip
- popd
- mv pkg/apple/build/Release/RetroArch.zip ${XCPROJECT_NAME}.zip
- mkdir .retroarch-repo
- "cp -r ./* .retroarch-repo"
- "mv .retroarch-repo/ retroarch-repo/"
build-retroarch-ios-arm64:
extends: .build-retroarch-macos-xcode
variables:
@@ -795,6 +818,23 @@ build-static-retroarch-dummy-psp:
- "cp -f pkg/psp1/ICON0.PNG ${MEDIA_PATH}/${CI_PROJECT_NAME}/pkg"
- "cp -f pkg/psp1/PIC1.PNG ${MEDIA_PATH}/${CI_PROJECT_NAME}/pkg"
build-static-retroarch-djgpp:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-djgpp-build-container:latest
stage: prepare-for-static-cores
before_script:
- export NUMPROC=$(($(nproc)/3))
artifacts:
paths:
- retroarch-precompiled/
expire_in: 10 min
dependencies: []
script:
# Allow failure since we don't have a core
- "make -f Makefile.dos -j$NUMPROC ||:"
- "mkdir .retroarch-precompiled"
- "cp -r ./* .retroarch-precompiled/"
- "mv .retroarch-precompiled/ retroarch-precompiled/"
build-static-retroarch-ctr:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-devkitpro:latest
stage: prepare-for-static-cores
+117 -17
View File
@@ -1,12 +1,112 @@
# Future
# 1.10.2
- 3DS: Add a menu toggle for switching between old and new 3DS speeds, located in the 'Power Management' menu. Enabled by default, hidden on old 3DS devices.
- AUDIO/MIXER: Free audio voices properly
- CHEEVOS: Update to rcheevos 10.3.3
- CHEEVOS: Support for Arduboy
- CHEEVOS: Fix tab sequences in rich presence being turned into t character
- CHEEVOS: Fix overflow when parsing float value that has more than 9 digits after the decimal
- CHEEVOS: Fix memory mapping when disconnect mask breaks a region into multiple blocks
- CORES: Enable manual selection of which cores are displayed in the 'Standalone Cores' menu
- DATABASE/EXPLORE: Added more categories to the Explore menu
- INPUT: Fix analog stick not working with 'Unified Menu Controls'
- INPUT/MAPPING: Add 'Manage Remap Files' submenu + automatically save input remaps when closing content
- INPUT/MAPPING: Add 'Reset Input Mapping' option to 'Manage Remap Files' menu
- INPUT/MAPPING: Fix keyboard device remap nulling
- IOS/IOS13+: Support a toolbar that allows toggling of onscreen keyboard and touch mouse
- LIBRETRO: RETRO_ENVIRONMENT_SHUTDOWN fix - ensure core is properly unloaded when RETRO_ENVIRONMENT_SHUTDOWN is called
- LIBRETRO: RETRO_ENVIRONMENT_SHUTDOWN fix - ensure menu stack is properly flushed when RETRO_ENVIRONMENT_SHUTDOWN is called
- LINUX/MALI FBDEV: Fix segfault switching video threaded from quickmenu
- LOCALIZATION: Add Czech language support
- MMAP: Handle disconnect bits on both sides of len
- MIYOO: Improve CPU architecture and model name identification for Miyoo
- MENU/SETTINGS: Remove 'Advanced Settings' flag from 'Settings > Core' menu
- MENU/MATERIALUI: Add 'Gray Dark + Light' themes
- MENU/RGUI: Add 6x10 extended ASCII and Latin Extended A and B fonts. These will enable most Latin alphabets to be displayed in RGUI.
- MENU/RGUI: Add 'Gray Dark + Light' themes
- MENU/XMB: Add title margin adjustment
- MENU/XMB: Vertical fade corrections
- MENU/OZONE: The size of the thumbnail bar can now be changed though a new option (Settings->User interface->Appearance) up to double its normal size.
- MENU/OZONE: Add 'Gray Dark + Light' themes
- MENU/OZONE: Add thumbnail scale option
- HOTKEYS: Added hotkey for toggling sync to exact content framerate
- HOTKEYS: Prevent log spam when using rewind hotkey with cores that don't support rewind, if rewind functionality itself is disabled
- HOTKEYS: Add hotkey for toggling sync to exact content framerate
- PS3/PSL1GHT: Add RSX graphics support
- PS3/PSL1GHT: Add libco support
- PS3/PSL1GHT: Add experimental PSMove support
- RS90: Optimise layout of sdl_rs90_video
- STEAM: Use native OSK (Onscreen Keyboard) instead of built-in RetroArch version
- STEAM: New built-in core DLC downloader
- STEAM: Swap OK/Cancel buttons by default
- VIDEO/HDR: Removed redundant copy of buffer in HDR mode if the shader has already a HDR format i.e. R10G10B10A2 (updated Vulkan/D3D11/D3D12 drivers)
- VIDEO/HDR: Fixed crash when using stock shader and HDR and previous optimisation
- WAYLAND: Dynamically load libdecor at runtime
- WAYLAND: Fix splash screen when using xdg_toplevel
- WAYLAND: SHM anti-collision for the splash screen
- WAYLAND: Skip splash screen if window is not ready
- WII: Fix find_connection_entry(): needs unsigned int
Otherwise the USB gamepad cannot be found, if VID/PID has leading zero. This issue happened with Retrode gamepad adapter
- WII: Rework Retrode gamepad implementation to support multi_pad interface
- WII: Fix - Unplugging and re-plugging now works again
- WII: vWii- Only gamepad 1 is supported, because multi_pad is currently only relevant in the Wii U implementation
- WIIU: Implemented the multi_pad interface according to input/connect/connect_wiiugca.c
- WIIU: Add Optimize for Gamepad option
- WIIU: Fix USB gamepad support
# 1.10.1
- ANDROID: Add `HAVE_LANGEXTRA` back to makefile
- ANDROID: Include adaptive launcher icons
- ANDROID: Populate external storage devices inside the file browser on Android 11+ devices
- CHEEVOS: add mastery placard
- CHEEVOS: more description message for missing RetroAchievements credentials
- CHEEVOS: prevent occasional infinite wait loading multi-disc game from secondary disc
- CHEEVOS: stop load process if unable to retrieve achievement data
- CHEEVOS: support for identifying Dreamcast CHDs
- CHEEVOS: Updated to 10.3.2
- CONTENTLESS CORES: Disable per-game and per-content-directory remaps when running contentless cores
- CONTENTLESS CORES: Disable per-game and per-content-directory shader presets
- CONTENTLESS CORES: Enable config overrides
- CONTENTLESS CORES: Enable runtime logging
- CORE INFORMATION: Show core version
- CORE UPDATER: Add 'Core System Files Downloader'
- CORES/SETTINGS: Add 'Standalone Cores' menu
- D3D10/D3D11: Add Vsync swap interval
- EMSCRIPTEN: Enable 7zip
- GBA: New GBA filter Upscale_240x160-320x240
- GONG: Removed now that it's a standalone core
- HISTORY/FAVORITES: Fix default core on 'Add to Favorites'
- INPUT/WAYLAND: Allow toggling mouse grabs
- INPUT/WAYLAND: Release keys and mouse buttons on lost focus
- iOS: Support for custom keyboard and touch mouse support, among other iOS 13 features
- LIBRETRO: Fix crash when cores using RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK return false from retro_load_game()
- LIBRETRO: Add optional frame skipping when fast-forwarding
- LOCALIZATION: Fetch translations from Crowdin
- LOCALIZATION: OSD fonts for Chinese, Korean, Arabic and Persian
- LOCALIZATION: Translation fixes for various languages
- MENU/RGUI: Add dynamic theme
- MIYOO: Enable NEAREST audio resampler
- MIYOO: Support battery level
- NETPLAY: Disable savestates on stateless mode
- NGC/Wii: Several improvements
- OSX: Enable compilation on PPC
- OZONE/XMB: Improve efficiency/accuracy of History/Favorites icon rendering
- RECORDING/FFMPEG: Fix building against FFmpeg 5.0
- RETROARCH INFORMATION: No longer report on enabled Python support, which was removed in RetroArch 1.7.8
- SAVESTATES: Disable save states based on save state support level defined in core info files
- UNIX/WINDOWS: Allow setting the default libretro_directory via environment variable
- WAYLAND/VULKAN: Fix Wayland Vulkan not reacting to initial resize
- WINDOWS/WINRAW: Enable mouse overlay control
- Xbox/UWP: Fix CHD not working with Cheevos / Add 7zip support.
# 1.10.0
- 3DS: Add Jaxe, A5200 and WASM4 cores
- 3DS: Fix rotation
- ARCHIVE: Allow loading files from archive subdirectory
- AUDIO: Remove frame limit from audio batch callback. Before, if a core used the audio batch callback, there would be a hidden cap of 1024 on the number of audio frames that could be sent. If a core exceeded this value, any excess samples were silently discarded. While this is sufficient for 'normal' samplerates/framerates, it means that e.g. a core using the batch callback to send 44100 Hz audio at 30 fps with would have entirely broken sound. This has been fixed by removing the audio batch frame limit.
- AUDIO/RESAMPLER/NEON: Implement sinc kaiser NEON function
- CHEEVOS: Reset hardcore default to enabled; show message when trying to load state in hardcore
- CHEEVOS: Reset hardcore default to enabled; show message when trying to load state in hardcore
- CHEEVOS: Fix memory map conversion
- CHEEVOS: Check netplay status when unlocking achievements
- CHEEVOS: Support for hashing buffered NDS ROMs
@@ -29,7 +129,7 @@
- LOGGING: Log font rendering backend only once
- HOTKEYS: Added a hotkey toggle for the on-screen technical statistics.
- HOTKEYS: Add delay + acceleration to volume hotkeys
- MENU: Add option for showing notifications only in menu
- MENU: Add option for showing notifications only in menu
- MENU/RGUI: Add Finnish to supported languages
- MENU/XMB: Optional vertical list item fade
- MENU/XMB/OZONE: Category + History/Favorites icons
@@ -78,7 +178,7 @@
# 1.9.14
- ANDROID/PLAYSTORE: Implement MANAGE_EXTERNAL_STORAGE permission
- ANDROID/PLAYSTORE: Bump up SDK level to 30 to comply with Play Store policies
- AUDIO/MIXER: Increase sample buffer padding
- AUDIO/MIXER: Increase sample buffer padding
- CHEEVOS: Disallow achievements when spectating netplay
- CHEEVOS: Fix need-to-activate achievement logic for non-hardcore
- CHEEVOS: Don't queue rewind re-init if already on main thread
@@ -87,17 +187,17 @@
- CHEEVOS: Validate hashes for secondary discs in multi-disc games
- CHEEVOS: Ensure placard is initialized on main thread when game has no achievements
- CHEEVOS: Audit achievement settings defaults and visibility
- CHEEVOS: Show error message when no password provided
- CHEEVOS: Show error message when no password provided
- CHEEVOS: Use widget for game loaded achievement progress
- CONFIG: Honor config_save_on_exit when Reboot/Shutdown is called
- DISK CONTROL: Focus on current content entry in Disk Control append/insert
- FRAMEDELAY: Auto Frame Delay Improvements - swap interval handling, D3DX handling, and delay target resets also on core restart. It should now work with high refresh rates and also with Direct3D 10/11/12 drivers
- INPUT/GYRO/ACCELEROMETER/ANDROID: Re-enable Gyroscope & Accelerometer when RetroArch resumes or regains focus
- INPUT/HID: Fix gamepad disconnect on unrecognized HID device
- INPUT/HID: Fix gamepad disconnect on unrecognized HID device
- LAKKA: Patch to fix keyboard typing
- LAKKA: CD-ROM eject menu item
- LAKKA/BLUETOOTH: Add option to remove pairing
- LAKKA/SWITCH: Disable rumble gain
- LAKKA/BLUETOOTH: Add option to remove pairing
- LAKKA/SWITCH: Disable rumble gain
- LAKKA/SWITCH: Disable cpu scaling, uses its own CPU governor
- LOGGING: Logging cleanups. A bunch of unifications and reformattings (capitalizations, dots, quotes, prefixes etc). Also added a few missing things, such as Run-Ahead error logging and LED interface init logging when it is enabled.
- NETPLAY: Networking - should not print country for a local lobby
@@ -108,7 +208,7 @@
- NETWORK: Make HTTP header parsing case insensitive
- NETWORK/UPNP: Fixed memory leaks
- NETWORK/UPNP: Added a task_queue_wait to prevent executing two nat tasks at once, so it's also thread safe now
- NETWORK/UPNP: Switch to a permanent lease time, but request it to be removed when we do netplay_free. Switch to a permanent lease time, but request it to be removed when we do netplay_free.
- NETWORK/UPNP: Switch to a permanent lease time, but request it to be removed when we do netplay_free. Switch to a permanent lease time, but request it to be removed when we do netplay_free.
- NETWORK/UPNP: Only use a single interface for UPnP, return on the first one found instead of iterating over all of them and opening them one by one
- OVERLAYS: Revert changes
- RETROFW: Add OSS audio
@@ -395,7 +495,7 @@ Not that SR works on them but to fix RA compile issues
# 1.9.5
- ALSATHREAD: Make alsathread default for all ALSA devices with threads
- ARCHIVE: Fix loading of archived content with file names containing '#' characters
- CHEEVOS: Upgrade to rcheevos 10.1
- CHEEVOS: Upgrade to rcheevos 10.1
- CHEEVOS: Challenge indicators
- CHEEVOS: Group achievements by category in quick menu
- CHEEVOS: Relabel 'Start Active' with 'Encore Mode'
@@ -410,9 +510,9 @@ Not that SR works on them but to fix RA compile issues
- INPUT: Allow the 8 analog stick directions to be used as keys for core keyboard mappings
- LIBRETRO: Add API extension for setting 'need_fullpath' based on content file extension and to request persistent frontend content data buffers
- MENU/SEARCH: Add enhanced search functionality to the 'Manage Cores' menu
- OPENDINGUX: Fix black screens when triggering gfx driver initialisation via menu actions
- OPENDINGUX: Fix black screens when triggering gfx driver initialisation via menu actions
- UNIX: Get better battery stats on sysfs nodes
- VIDEO: Extend Frame Delay range to 19 to accommodate PAL land too
- VIDEO: Extend Frame Delay range to 19 to accommodate PAL land too
- WIFI/LAKKA: Add nmcli to wifi drivers
- WIFI/LAKKA: Add wifi configuration menu
- X11: fix fullscreen when swapping monitors/resolution
@@ -445,7 +545,7 @@ Not that SR works on them but to fix RA compile issues
- CORE INFO/FILE IO: Core Info cache; significant file I/O performance improvements on systems with slow disk file I/O
- CORE INFO/FILE IO: Enable core info cache by default on all 'console' platforms
- FREEBSD: FreeBSD build fix
- LAKKA: Support for tweaking CPU governors/scaling policies
- LAKKA: Support for tweaking CPU governors/scaling policies
- LAKKA: This adds managed policies and settings to store them and reload them at startup
- LIBRETRO API: Add API extension for cores to override frontend fast-forward state
- MENU/RGUI: Fix saving of config files/overrides when 'Lock Menu Aspect Ratio' is enabled
@@ -486,7 +586,7 @@ Not that SR works on them but to fix RA compile issues
- MENU: Add optional menu screensaver
- MENU: Add search filter support to cheats and overlays file browser menus
- MENU/FILEBROWSER: Enhanced 'Load Content' file browser search functionality
- MENU/INPUT: Block accidental diagonals in menu navigation
- MENU/INPUT: Block accidental diagonals in menu navigation
- MENU/RGUI: Add option to disable menu transparency
- MENU/RGUI: Fix display of 'Video > Scaling' menu when 'Lock Menu Aspect Ratio' is enabled
- MENU/MATERIALUI: Add icon to 'Turbo Fire' menu entry
@@ -605,7 +705,7 @@ Having remaps for many different cores makes finding the active core files cumbe
- MAC/UNIVERSAL: Add CoreAudio3 audio driver for Metal Universal build
- MAC/IOS: Only extract assets once on first install
- MENU: Add 'L2 + R2' menu toggle gamepad combo
- MENU: Menu text improvements; clarifications, consistency, text mistakes,
- MENU: Menu text improvements; clarifications, consistency, text mistakes,
- MENU: Tweak menu scroll initial hold delays
- MENU: Restrict menu acceleration to navigation buttons
- MENU: Add 'Menu Driver' setting to 'User Interface'
@@ -822,7 +922,7 @@ save state limit (global). Instead of wrapping around the slot counter it will s
- FILE PATH: Various file path handling optimisations
- FONT: Fix Arabic, Chinese and Korean font rendering
- INPUT MAPPING/REMAPPING: Restore broken 'reset to default' functionality with RetroPad 'start' button
- INPUT MAPPING/REMAPPING: Fix 'reset to default' action for analog sticks and undefined core inputs
- INPUT MAPPING/REMAPPING: Fix 'reset to default' action for analog sticks and undefined core inputs
- LOCALIZATION: Update Arabic translation
- LOCALIZATION: Update Chinese (Simplified) translation
- LOCALIZATION: Update Chinese (Traditional) translation
@@ -1084,7 +1184,7 @@ appear to be required in order for mouse input to work on macOS
- VITA: Re-add Online Updater
- VULKAN: Fix font driver 'vulkan_get_message_width()' function
- VIDEO FILTERS: Only use threads when the number exceeds 1. Fixes race conditions with some CPU filters on Vita
- WINDOWS: Add ANGLE support for x64, separate binary (for now?)
- WINDOWS: Add ANGLE support for x64, separate binary (for now?)
# 1.8.2
- BUG/CRASH/GLSLANG: Fix glslang crashing error - managed to reproduce an issue which has been plaguing
@@ -1261,7 +1361,7 @@ Vulkan, so use the old onContentRectChanged callback to get notified when size c
# (1.7.9)
- AI SERVICE: Image mode is now much faster, it now saves the image in-memory in PNG format then passes it along to the translation service
- BUGFIX: Touch input - When using an overlay to toggle the quick menu on touchscreen devices, we no longer get 'phantom' menu input - i.e. the old bug of hitting the toggle and instantly resuming content (or performing a save state) is fixed
- BUGFIX: Networking - RetroArch crashed when pressing left while Relay Server Location entry was selected
- BUGFIX: Networking - RetroArch crashed when pressing left while Relay Server Location entry was selected
- BUGFIX: Networking - fix memory leak that could happen at exit after a network
operation had run
- CHEEVOS: Improve handling of line endings when calculating CD hashes for retroachievements
+17 -11
View File
@@ -339,6 +339,7 @@ endif
OBJ += \
gfx/drivers_font_renderer/bitmapfont.o \
gfx/drivers_font_renderer/bitmapfont_10x10.o \
gfx/drivers_font_renderer/bitmapfont_6x10.o \
tasks/task_autodetect.o \
input/input_autodetect_builtin.o \
input/input_keymaps.o \
@@ -472,7 +473,8 @@ ifeq ($(HAVE_LANGEXTRA), 1)
intl/msg_hash_fi.o \
intl/msg_hash_id.o \
intl/msg_hash_sv.o \
intl/msg_hash_uk.o
intl/msg_hash_uk.o \
intl/msg_hash_cs.o
endif
ifneq ($(HAVE_GETOPT_LONG), 1)
@@ -1088,7 +1090,8 @@ ifeq ($(HAVE_MENU_COMMON), 1)
menu/cbs/menu_cbs_label.o \
menu/cbs/menu_cbs_sublabel.o \
menu/cbs/menu_cbs_title.o \
menu/menu_displaylist.o
menu/menu_displaylist.o \
menu/menu_contentless_cores.o
endif
ifeq ($(HAVE_GFX_WIDGETS), 1)
@@ -1260,6 +1263,7 @@ ifeq ($(HAVE_WAYLAND), 1)
OBJ += gfx/drivers_context/wayland_ctx.o \
input/common/wayland_common.o \
input/drivers/wayland_input.o \
gfx/common/wayland_common.o \
gfx/common/wayland/xdg-shell.o \
gfx/common/wayland/idle-inhibit-unstable-v1.o \
gfx/common/wayland/xdg-decoration-unstable-v1.o
@@ -1272,8 +1276,7 @@ ifeq ($(HAVE_WAYLAND), 1)
LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS)
ifeq ($(HAVE_LIBDECOR), 1)
DEFINES += -DHAVE_LIBDECOR
LIBS += $(LIBDECOR_LIBS)
DEFINES += -DHAVE_LIBDECOR_H
DEF_FLAGS += $(LIBDECOR_CFLAGS)
endif
@@ -2073,12 +2076,6 @@ OBJ += $(LIBRETRO_COMM_DIR)/formats/bmp/rbmp_encode.o \
$(LIBRETRO_COMM_DIR)/formats/image_transfer.o \
$(LIBRETRO_COMM_DIR)/formats/m3u/m3u_file.o
# Gong embedded core
ifeq ($(HAVE_GONG),1)
DEFINES += -DHAVE_GONG
OBJ += cores/libretro-gong/gong.o
endif
# Video4Linux 2
ifeq ($(HAVE_V4L2),1)
@@ -2175,6 +2172,7 @@ ifeq ($(HAVE_NETWORKING), 1)
deps/rcheevos/src/rcheevos/runtime_progress.o \
deps/rcheevos/src/rcheevos/trigger.o \
deps/rcheevos/src/rcheevos/value.o \
deps/rcheevos/src/rhash/cdreader.o \
deps/rcheevos/src/rhash/hash.o \
deps/rcheevos/src/rapi/rc_api_common.o \
deps/rcheevos/src/rapi/rc_api_runtime.o \
@@ -2394,7 +2392,8 @@ ifeq ($(HAVE_STATIC_VIDEO_FILTERS), 1)
gfx/video_filters/dot_matrix_4x.o \
gfx/video_filters/upscale_1_5x.o \
gfx/video_filters/upscale_256x_320x240.o \
gfx/video_filters/picoscale_256x_320x240.o
gfx/video_filters/picoscale_256x_320x240.o \
gfx/video_filters/upscale_240x160_320x240.o
endif
ifeq ($(WANT_IOSUHAX), 1)
@@ -2459,6 +2458,13 @@ ifeq ($(ANDROID), 1)
OBJ += play_feature_delivery/play_feature_delivery.o
endif
### Steam integration using mist
ifeq ($(HAVE_MIST), 1)
INCLUDE_DIRS += -I$(MIST_PATH)/include
LDFLAGS += -L$(MIST_PATH) -lmist
OBJ += steam/steam.o tasks/task_steam.o
endif
##################################
### Classic Platform specifics ###
###############WIP################
+217
View File
@@ -0,0 +1,217 @@
include version.all
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
TOPDIR ?= $(CURDIR)
DEBUG ?= 0
WHOLE_ARCHIVE_LINK = 0
GRIFFIN_BUILD = 0
OBJ :=
DEFINES := -DHAVE_DJGPP=1 -U__linux__ -U__linux -DRARCH_INTERNAL -DHAVE_STB_VORBIS
CC := i586-pc-msdosdjgpp-gcc
CXX := i586-pc-msdosdjgpp-g++
TARGET := retrodos.exe
RARCH_CONSOLE = 0
HAVE_SHADERPIPELINE = 1
HAVE_SPIRV_CROSS = 0
HAVE_PATCH = 1
HAVE_LUA = 0
HAVE_CONFIGFILE = 1
HAVE_GFX_WIDGETS = 1
HAVE_LANGEXTRA = 1
HAVE_DR_MP3 = 1
HAVE_TRANSLATE = 0
HAVE_SCREENSHOTS = 1
HAVE_REWIND = 1
HAVE_AUDIOMIXER = 1
HAVE_CC_RESAMPLER = 1
HAVE_MENU_COMMON = 1
HAVE_RTGA = 1
HAVE_RPNG = 1
HAVE_RJPEG = 1
HAVE_RBMP = 1
HAVE_7ZIP = 1
HAVE_ZLIB = 1
HAVE_IMAGEVIEWER = 1
HAVE_BUILTINZLIB = 1
HAVE_LIBRETRODB = 1
HAVE_DSP_FILTER = 1
HAVE_VIDEO_FILTER = 1
HAVE_STATIC_VIDEO_FILTERS = 1
HAVE_STATIC_AUDIO_FILTERS = 1
HAVE_FILTERS_BUILTIN = 1
HAVE_MENU = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_CHEATS = 1
HAVE_RUNAHEAD = 1
HAVE_NETWORKING = 0
HAVE_NETPLAYDISCOVERY = 1
HAVE_OVERLAY := 1
HAVE_STB_FONT = 1
HAVE_COMMAND := 1
HAVE_STDIN_CMD := 1
HAVE_CMD := 1
HAVE_CHEEVOS = 0
HAVE_CHD = 0 # disabled due to static libretro-common and libchdr conflicts between different cores
HAVE_STB_VORBIS = 1
HAVE_IBXM = 1
HAVE_CORE_INFO_CACHE = 1
HAVE_RGUI = 1
HAVE_MATERIALUI = 0
HAVE_XMB = 0
HAVE_OZONE = 0
OBJ := \
frontend/drivers/platform_dos.o \
gfx/drivers/vga_gfx.o gfx/drivers_font/vga_font.o \
input/drivers/dos_input.o input/drivers_joypad/dos_joypad.o
include Makefile.common
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := $(CURDIR)/source
DATA := data
INCLUDES := include
EXEFS_SRC := exefs_src
APP_TITLE := RetroArch
APP_VERSION := $(RARCH_VERSION)
APP_AUTHOR := libretro Team
APP_ICON := pkg/libnx/retroarch.jpg
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH :=
CFLAGS := -g -Wall -O3 -fcommon -ffast-math -ffunction-sections \
$(ARCH) $(DEFINES) $(INCLUDE_DIRS)
CFLAGS += $(INCLUDE)
ifeq ($(HAVE_FILTERS_BUILTIN), 1)
CFLAGS += -DHAVE_FILTERS_BUILTIN
endif
ifeq ($(strip $(HAVE_STATIC_DUMMY)),1)
CFLAGS += -DHAVE_STATIC_DUMMY=1
endif
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = $(ARCH) -Wl,--allow-multiple-definition -Wl,-Map,$(notdir $*.map)
# add things from Makefile.common
CFLAGS += $(DEF_FLAGS)
LIBS := -lstdc++ -lm
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
export OFILES := $(OBJ)
ifeq ($(strip $(HAVE_STATIC_DUMMY)),)
OFILES += libretro_libnx.a
endif
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
DEPENDS_TMP := $(OFILES:.o=.d)
DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP))
.PHONY: clean all
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT)
$(OUTPUT): $(OBJ)
$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) -L. -lretro_dos $(LIBS)
%.o: %.c
$(CC) -c -o $@ $(CFLAGS) $<
%.o: %.cpp
$(CXX) -c -o $@ $(CFLAGS) $<
clean:
rm -f $(DEPENDS) $(OBJ) $(OUTPUT)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
+1
View File
@@ -43,6 +43,7 @@ HAVE_CONFIGFILE = 1
HAVE_CHEATS = 1
HAVE_IBXM = 1
HAVE_CORE_INFO_CACHE = 1
HAVE_7ZIP = 1
ASYNC ?= 0
ifeq ($(LIBRETRO), mupen64plus)
+10 -46
View File
@@ -66,7 +66,6 @@ SHADER_CG_DIR := media/shaders_cg
OVERLAY_DIR := media/overlays
SHADER_GLSL_DIR := media/shaders_glsl
PYTHON2 := python2$(EXE_EXT)
PYTHON3 := python3$(EXE_EXT)
GIT := git$(EXE_EXT)
@@ -122,14 +121,20 @@ else ifeq ($(libogc_platform), 1)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
LD = $(DEVKITPPC)/bin/powerpc-eabi-ld$(EXE_EXT)
ELF2DOL = $(DEVKITPPC)/bin/elf2dol$(EXE_EXT)
# Check whether ELF2DOL executable exists
# (path has changed in more recent toolchains)
ifeq ("$(wildcard $(ELF2DOL))","")
ELF2DOL = $(DEVKITPRO)/tools/bin/elf2dol$(EXE_EXT)
endif
EXT_TARGET := $(TARGET_NAME)_$(platform).dol
EXT_INTER_TARGET := $(TARGET_NAME)_$(platform).elf
INCLUDE += -I. -I$(DEVKITPRO)/libogc/include -Iwii/libogc/include
INCLUDE += -I.
ifeq ($(EXTERNAL_LIBOGC), 1)
CFLAGS += -DEXTERNAL_LIBOGC
CXXFLAGS += -DEXTERNAL_LIBOGC
INCLUDE += -I$(DEVKITPRO)/libogc/include
ifeq ($(platform), ngc)
LIBDIRS += -L$(DEVKITPRO)/libogc/lib/cube
@@ -140,6 +145,7 @@ else ifeq ($(libogc_platform), 1)
else
CFLAGS += -DINTERNAL_LIBOGC
CXXFLAGS += -DINTERNAL_LIBOGC
INCLUDE += -Iwii/libogc/include
ifeq ($(platform), ngc)
LIBDIRS += -Lwii/libogc/libs/cube
@@ -935,7 +941,7 @@ else ifeq (qnx,$(platform))
LDFLAGS += -g
endif
PLATCFLAGS += -DHAVE_SHADERPIPELINE -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_OZONE -DHAVE_CC_RESAMPLER -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_FBO -DHAVE_GL_SYNC -DHAVE_GLSLANG -DHAVE_BUILTINGLSLANG -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_RUNAHEAD -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_XMB -DRARCH_INTERNAL -DWANT_GLSLANG -DHAVE_XCB -DHAVE_EGL -DHAVE_BB10 -DHAVE_GLSL -DHAVE_AL -DHAVE_BSV_MOVIE -DRARCH_MOBILE
PLATCFLAGS += -DHAVE_SHADERPIPELINE -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_OZONE -DHAVE_CC_RESAMPLER -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_GL_SYNC -DHAVE_GLSLANG -DHAVE_BUILTINGLSLANG -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_RUNAHEAD -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_XMB -DRARCH_INTERNAL -DWANT_GLSLANG -DHAVE_XCB -DHAVE_EGL -DHAVE_BB10 -DHAVE_GLSL -DHAVE_AL -DHAVE_BSV_MOVIE -DRARCH_MOBILE
EXT_TARGET := $(TARGET_NAME)
EXT_INTER_TARGET := $(TARGET_NAME)
INCLUDE += -Ilibretro-common/include -Igfx/include -Ideps -Ideps/stb -Ideps/rcheevos/include -Ideps/SPIRV-Cross -Ideps/glslang -I.
@@ -973,53 +979,11 @@ else ifneq (,$(findstring unix,$(platform)))
HAVE_CHEATS := 1
HAVE_CORE_INFO_CACHE := 1
PLATCFLAGS += -D__MMX__ -D__SSE__ -DHAVE_OPENGL -DHAVE_OPENGL1 -DHAVE_GLSL -DHAVE_SHADERPIPELINE -DHAVE_OZONE -DHAVE_CC_RESAMPLER -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_FBO -DHAVE_GL_SYNC -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_BUILTINGLSLANG -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_RUNAHEAD -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_VULKAN -DHAVE_XMB -DRARCH_INTERNAL -DWANT_GLSLANG -DHAVE_X11 -DHAVE_XCB -DHAVE_UDEV -DHAVE_BSV_MOVIE -DHAVE_PULSE
PLATCFLAGS += -D__MMX__ -D__SSE__ -DHAVE_OPENGL -DHAVE_OPENGL1 -DHAVE_GLSL -DHAVE_SHADERPIPELINE -DHAVE_OZONE -DHAVE_CC_RESAMPLER -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_GL_SYNC -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_BUILTINGLSLANG -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_RUNAHEAD -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_VULKAN -DHAVE_XMB -DRARCH_INTERNAL -DWANT_GLSLANG -DHAVE_X11 -DHAVE_XCB -DHAVE_UDEV -DHAVE_BSV_MOVIE -DHAVE_PULSE
EXT_TARGET := $(TARGET_NAME)
EXT_INTER_TARGET := $(TARGET_NAME)
INCLUDE += -Ilibretro-common/include -Igfx/include -Ideps -Ideps/stb -Ideps/rcheevos/include -Ideps/SPIRV-Cross -Ideps/glslang -I.
LIBS += -ldl -lm -lpthread -lGL -ludev -lpulse -lX11 -lX11-xcb -lXxf86vm
else ifeq (dos,$(platform))
HAVE_RPNG := 1
HAVE_RJPEG := 1
HAVE_RBMP := 1
HAVE_RTGA := 1
HAVE_ZLIB := 1
HAVE_7ZIP := 1
HAVE_NETWORKING := 0
HAVE_NETWORK_CMD := 0
HAVE_NETPLAYDISCOVERY := 0
HAVE_OVERLAY := 1
HAVE_VIDEO_LAYOUT := 0
HAVE_MATERIALUI := 0
HAVE_XMB := 0
HAVE_STB_FONT := 1
HAVE_THREADS := 0
HAVE_LIBRETRODB := 1
HAVE_COMMAND := 1
HAVE_STDIN_CMD := 1
HAVE_CMD := 1
HAVE_DYLIB := 0
HAVE_DYNAMIC := 0
HAVE_GRIFFIN_CPP := 0
WANT_GLSLANG := 0
HAVE_CONFIGFILE := 1
HAVE_PATCH := 0
HAVE_CHEATS := 0
HAVE_CORE_INFO_CACHE := 1
CC=i586-pc-msdosdjgpp-gcc
CXX=i586-pc-msdosdjgpp-g++
ifeq ($(DEBUG), 1)
LDFLAGS += -g
endif
PLATCFLAGS += -DHAVE_SHADERPIPELINE -DHAVE_CC_RESAMPLER -DRC_DISABLE_LUA -DHAVE_FBO -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DRARCH_INTERNAL -DHAVE_XCB
TARGET_NAME := retrodos
EXT_TARGET := $(TARGET_NAME).exe
EXT_INTER_TARGET := $(TARGET_NAME).exe
INCLUDE += -Ilibretro-common/include -Igfx/include -Ideps -Ideps/stb -Ideps/SPIRV-Cross -Ideps/glslang -I.
LIBS += -lm
LIBDIRS += -L.
endif
ifneq (,$(findstring msvc,$(platform)))
+1 -1
View File
@@ -111,7 +111,7 @@ HAVE_CHEEVOS = 0
HAVE_LIBSHAKE = 0
HAVE_CORE_INFO_CACHE = 1
#HAVE_TINYALSA = 1
#HAVE_NEAREST_RESAMPLER = 1
HAVE_NEAREST_RESAMPLER = 1
OS = Linux
TARGET = retroarch
+20 -125
View File
@@ -63,16 +63,18 @@ ifeq ("$(wildcard $(ELF2DOL))","")
ELF2DOL = $(DEVKITPRO)/tools/bin/elf2dol$(EXE_EXT)
endif
INCLUDE += -I. -I$(DEVKITPRO)/libogc/include -Iwii/libogc/include
INCLUDE += -I.
ifeq ($(EXTERNAL_LIBOGC), 1)
CFLAGS += -DEXTERNAL_LIBOGC
CXXFLAGS += -DEXTERNAL_LIBOGC
LIBDIRS += -L$(DEVKITPRO)/libogc/lib/cube
INCLUDE += -I$(DEVKITPRO)/libogc/include
else
CFLAGS += -DINTERNAL_LIBOGC
CXXFLAGS += -DINTERNAL_LIBOGC
LIBDIRS += -Lwii/libogc/libs/cube
INCLUDE += -Iwii/libogc/include
endif
ifeq ($(GX_PTHREAD_LEGACY), 1)
@@ -127,18 +129,31 @@ HAVE_RWAV := 1
RARCH_CONSOLE = 1
HAVE_CHEATS := 1
HAVE_CORE_INFO_CACHE := 1
HAVE_MENU_COMMON := 1
HAVE_MENU := 1
HAVE_BUILTINZLIB := 1
HAVE_STATIC_AUDIO_FILTERS := 1
HAVE_STATIC_VIDEO_FILTERS := 1
HAVE_XMB := 0
HAVE_OZONE := 0
HAVE_RGUI := 1
HAVE_MATERIALUI := 0
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
INCLUDE += -I./libretro-common/include \
-Ideps \
-Ideps/stb
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
OBJ = griffin/griffin.o $(PLATOBJS)
OBJ = $(PLATOBJS) audio/drivers/gx_audio.o gfx/drivers/gx_gfx.o input/drivers/gx_input.o frontend/drivers/platform_gx.o input/drivers_joypad/gx_joypad.o
ifeq ($(HAVE_GRIFFIN_CPP), 1)
OBJ += griffin/griffin_cpp.o
ifeq ($(EXTERNAL_LIBOGC), 0)
OBJ += wii/libogc/libfat/libfat.o wii/libogc/libfat/fatfile.o wii/libogc/libfat/file_allocation_table.o wii/libogc/libfat/cache.o wii/libogc/libfat/fatdir.o wii/libogc/libfat/partition.o wii/libogc/libfat/directory.o wii/libogc/libfat/filetime.o wii/libogc/libfat/disc.o
endif
include Makefile.common
CFLAGS += $(DEFINES)
ifeq ($(WANT_GLSLANG), 1)
OBJ += griffin/griffin_glslang.o
endif
@@ -156,18 +171,10 @@ ifeq ($(HAVE_WIIUSB_HID), 1)
CFLAGS += -DHAVE_WIIUSB_HID -DHAVE_HID
endif
ifeq ($(HAVE_LIBRETRODB), 1)
CFLAGS += -DHAVE_LIBRETRODB
endif
ifeq ($(BIG_STACK),1)
CFLAGS += -DBIG_STACK
endif
ifeq ($(HAVE_RJPEG), 1)
CFLAGS += -DHAVE_RJPEG
endif
ifeq ($(HAVE_FILE_LOGGER), 1)
CFLAGS += -DHAVE_FILE_LOGGER
endif
@@ -181,66 +188,10 @@ ifeq ($(HAVE_ZLIB), 1)
CFLAGS += -I./libretro-common/include/compat/zlib
endif
ifeq ($(HAVE_RPNG), 1)
CFLAGS += -DHAVE_RPNG
endif
ifeq ($(HAVE_RBMP), 1)
CFLAGS += -DHAVE_RBMP
endif
ifeq ($(HAVE_RTGA), 1)
CFLAGS += -DHAVE_RTGA
endif
ifeq ($(HAVE_IMAGEVIEWER), 1)
CFLAGS += -DHAVE_IMAGEVIEWER
endif
ifeq ($(HAVE_BSV_MOVIE), 1)
CFLAGS += -DHAVE_BSV_MOVIE
endif
ifeq ($(HAVE_RUNAHEAD), 1)
CFLAGS += -DHAVE_RUNAHEAD
endif
ifeq ($(HAVE_7ZIP), 1)
CFLAGS += -DHAVE_7ZIP -D_7ZIP_ST
endif
ifeq ($(HAVE_SCREENSHOTS), 1)
CFLAGS += -DHAVE_SCREENSHOTS
endif
ifeq ($(HAVE_REWIND), 1)
CFLAGS += -DHAVE_REWIND
endif
ifeq ($(HAVE_AUDIOMIXER), 1)
CFLAGS += -DHAVE_AUDIOMIXER
endif
ifeq ($(HAVE_RWAV), 1)
CFLAGS += -DHAVE_RWAV
endif
ifeq ($(HAVE_OVERLAY), 1)
CFLAGS += -DHAVE_OVERLAY
endif
ifeq ($(HAVE_VIDEO_LAYOUT), 1)
CFLAGS += -DHAVE_VIDEO_LAYOUT
endif
ifeq ($(HAVE_NETWORKING), 1)
CFLAGS += -DHAVE_NETWORKING
endif
ifeq ($(HAVE_NETPLAYDISCOVERY), 1)
CFLAGS += -DHAVE_NETPLAYDISCOVERY
endif
ifeq ($(RARCH_CONSOLE), 1)
CFLAGS += -DRARCH_CONSOLE
endif
@@ -251,50 +202,10 @@ endif
CFLAGS += -std=gnu99 -DHAVE_RGUI -DHAVE_MENU -DHAVE_GRIFFIN=1 -Wno-char-subscripts -DRARCH_INTERNAL
ifeq ($(HAVE_MATERIALUI), 1)
CFLAGS += -DHAVE_MATERIALUI
endif
ifeq ($(HAVE_XMB), 1)
CFLAGS += -DHAVE_XMB
endif
ifeq ($(HAVE_STB_FONT), 1)
CFLAGS += -DHAVE_STB_FONT
endif
ifeq ($(HAVE_LANGEXTRA), 1)
CFLAGS += -DHAVE_LANGEXTRA
endif
ifeq ($(HAVE_DSP_FILTER), 1)
CFLAGS += -DHAVE_DSP_FILTER
endif
ifeq ($(HAVE_VIDEO_FILTER), 1)
CFLAGS += -DHAVE_VIDEO_FILTER
endif
ifeq ($(HAVE_FILTERS_BUILTIN), 1)
CFLAGS += -DHAVE_FILTERS_BUILTIN
endif
ifeq ($(HAVE_THREADS), 1)
CFLAGS += -DHAVE_THREADS
endif
ifeq ($(HAVE_CONFIGFILE), 1)
CFLAGS += -DHAVE_CONFIGFILE
endif
ifeq ($(HAVE_PATCH), 1)
CFLAGS += -DHAVE_PATCH
endif
ifeq ($(HAVE_CHEATS), 1)
CFLAGS += -DHAVE_CHEATS
endif
ifeq ($(HAVE_RSOUND), 1)
CFLAGS += -DHAVE_RSOUND
endif
@@ -303,30 +214,14 @@ ifeq ($(HAVE_GETOPT_LONG), 1)
CFLAGS += -DHAVE_GETOPT_LONG=1
endif
ifeq ($(HAVE_DYLIB), 1)
CFLAGS += -DHAVE_DYLIB
endif
ifeq ($(HAVE_NETWORK_CMD), 1)
CFLAGS += -DHAVE_NETWORK_CMD
endif
ifeq ($(HAVE_COMMAND), 1)
CFLAGS += -DHAVE_COMMAND
endif
ifeq ($(HAVE_STDIN_CMD), 1)
CFLAGS += -DHAVE_STDIN_CMD
endif
ifeq ($(HAVE_DYNAMIC), 1)
CFLAGS += -DHAVE_DYNAMIC
endif
ifeq ($(HAVE_CORE_INFO_CACHE), 1)
CFLAGS += -DHAVE_CORE_INFO_CACHE
endif
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g -DDEBUG
else
+1 -1
View File
@@ -14,7 +14,7 @@ pnd: retroarch.pnd
install: all $(BINDIR)/retroarch-joyconfig $(BINDIR)/retroarch-zip $(PNDDIR)/readme.html
retroarch:
./configure --prefix=$PND_BASEDIR/$PRJ --disable-ffmpeg --disable-cg --disable-python --disable-libpng --disable-pulse --disable-jack --enable-gles --enable-xml
./configure --prefix=$PND_BASEDIR/$PRJ --disable-ffmpeg --disable-cg --disable-pulse --disable-jack --enable-opengles
make -f Makefile
$(BINDIR)/retroarch: retroarch
+5 -2
View File
@@ -31,11 +31,11 @@ endif
ifeq ($(SCREEN_DEBUG), 1)
LIBS += -ldebug
RARCH_DEFINES += -DSCREEN_DEBUG
DEFINES += -DSCREEN_DEBUG
endif
ifeq ($(BUILD_FOR_PCSX2), 1)
RARCH_DEFINES += -DBUILD_FOR_PCSX2
DEFINES += -DBUILD_FOR_PCSX2
endif
DEFINES += -DRARCH_INTERNAL -DRARCH_CONSOLE
@@ -57,6 +57,9 @@ else
HAVE_PATCH = 1
HAVE_CHEATS = 1
HAVE_RGUI = 1
HAVE_MATERIALUI = 0
HAVE_XMB = 0
HAVE_OZONE = 0
HAVE_ZLIB = 1
HAVE_NO_BUILTINZLIB = 1
HAVE_7ZIP = 1
+9 -2
View File
@@ -33,7 +33,7 @@ LIBDIRS += -L.
MACHDEP := -D__PSL1GHT__ -D__PS3__ -mcpu=cell
CFLAGS += -Wall $(MACHDEP) $(INCLUDE)
LDFLAGS := $(MACHDEP)
LIBS := -lretro_psl1ght -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs
LIBS := -lretro_psl1ght -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs -lfreetype -lcamera -lgem -lspurs
# system platform
system_platform = unix
@@ -53,7 +53,12 @@ else
GIT = git.exe
endif
OBJ = griffin/griffin.o
SHADER_OBJS = gfx/drivers/rsx_shaders/vpshader_basic.vpo.o \
gfx/drivers/rsx_shaders/fpshader_basic.fpo.o
LIBCO_OBJ = libretro-common/libco/ps3.o
OBJ = $(SHADER_OBJS) $(LIBCO_OBJ) griffin/griffin.o
ifeq ($(HAVE_LOGGER), 1)
CFLAGS += -DHAVE_LOGGER
@@ -92,7 +97,9 @@ SHARED_FLAGS += -DHAVE_MENU \
-DHAVE_SCREENSHOTS \
-DHAVE_REWIND \
-DHAVE_MULTIMAN \
-DHAVE_MEMINFO \
-DHAVE_RGUI \
-DHAVE_FREETYPE \
-DHAVE_CORE_INFO_CACHE
CFLAGS += -std=gnu99 $(SHARED_FLAGS)
CXXFLAGS += $(SHARED_FLAGS)
+15 -12
View File
@@ -4,8 +4,8 @@ DEBUG ?= 0
HAVE_KERNEL_PRX ?= 1
HAVE_THREADS ?= 1
BIG_STACK ?= 0
WHOLE_ARCHIVE_LINK ?= 0
LOAD_WITHOUT_CORE_INFO ?= 0
HAVE_STATIC_DUMMY ?= 0
TARGET = retroarchpsp
@@ -15,13 +15,8 @@ else
OPTIMIZE_LV := -O3
endif
ifeq ($(WHOLE_ARCHIVE_LINK), 1)
WHOLE_START := -Wl,--whole-archive
WHOLE_END := -Wl,--no-whole-archive
endif
INCDIR = deps deps/stb deps/7zip libretro-common/include libretro-common/include/compat/zlib
CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math -fsingle-precision-constant
CFLAGS = $(OPTIMIZE_LV) -ffast-math -fsingle-precision-constant
ASFLAGS = $(CFLAGS)
RARCH_DEFINES = -DPSP \
@@ -51,14 +46,21 @@ RARCH_DEFINES = -DPSP \
-DHAVE_CORE_INFO_CACHE
LIBDIR =
LDFLAGS =
LIBS = $(WHOLE_START) -lretro_psp1 $(WHOLE_END) -lstdc++ -lpspgu -lpspgum -lm -lpspaudio -lpspfpu -lpsppower -lpsprtc -lpthread-psp
LDFLAGS = -L$(shell psp-config --psp-prefix)
ifeq ($(HAVE_STATIC_DUMMY),1)
RARCH_DEFINES += -DHAVE_STATIC_DUMMY
else
LIBS += -lretro_psp1
endif
LIBS += -lstdc++ -lpspgu -lpspgum -lpspaudio -lpspfpu -lpsppower -lpsprtc -lpthread
ifeq ($(HAVE_THREADS), 1)
RARCH_DEFINES += -DHAVE_THREADS
endif
ifeq ($(HAVE_KERNEL_PRX), 1)
OBJS += bootstrap/psp1/kernel_functions.o
CFLAGS += -DHAVE_KERNEL_PRX
endif
@@ -75,9 +77,7 @@ CFLAGS += $(RARCH_DEFINES)
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = RetroArch PSP1
PSP_OBJECTS = griffin/griffin.o bootstrap/psp1/kernel_functions.o
OBJS = $(PSP_OBJECTS)
OBJS += griffin/griffin.o
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
@@ -96,3 +96,6 @@ pspsh-run:
debug: clean all pspsh-debug
run: clean all pspsh-run
sim:
/Applications/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL $(shell pwd)/EBOOT.PBP
+10 -5
View File
@@ -1,5 +1,6 @@
BUILD_PRX = 0
PSP_LARGE_MEMORY = 1
HAVE_KERNEL_PRX = 1
DEBUG = 0
TARGET = retroarchpsp_salamander
@@ -7,18 +8,18 @@ TARGET = retroarchpsp_salamander
ifeq ($(DEBUG), 1)
OPTIMIZE_LV := -O0 -g
else
OPTIMIZE_LV := -O2
OPTIMIZE_LV := -O3
endif
INCDIR = $(PSPPATH)/include libretro-common/include
CFLAGS = $(OPTIMIZE_LV) -G0 -std=gnu99 -ffast-math
CFLAGS = $(OPTIMIZE_LV) -ffast-math -fsingle-precision-constant
ASFLAGS = $(CFLAGS)
RARCH_DEFINES = -DPSP -DIS_SALAMANDER -DRARCH_CONSOLE
LIBDIR =
LDFLAGS =
LIBS = -lstdc++ -lm -lpsppower
LIBS = -lstdc++ -lpsppower
CFLAGS += $(RARCH_DEFINES)
@@ -45,8 +46,12 @@ OBJS = frontend/frontend_salamander.o \
libretro-common/vfs/vfs_implementation.o \
libretro-common/hash/lrc_hash.o \
libretro-common/time/rtime.o \
verbosity.o \
bootstrap/psp1/kernel_functions.o
verbosity.o
ifeq ($(HAVE_KERNEL_PRX), 1)
OBJS += bootstrap/psp1/kernel_functions.o
CFLAGS += -DHAVE_KERNEL_PRX
endif
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
+33 -127
View File
@@ -6,6 +6,7 @@ HAVE_FILE_LOGGER = 0
HAVE_CC_RESAMPLER = 1
WHOLE_ARCHIVE_LINK = 0
BIG_STACK = 1
HAVE_NETWORKING = 1
PC_DEVELOPMENT_IP_ADDRESS = 255.255.255.255
PC_DEVELOPMENT_UDP_PORT = 3490
RARCH_CONSOLE = 0
@@ -63,16 +64,18 @@ ifeq ("$(wildcard $(ELF2DOL))","")
ELF2DOL = $(DEVKITPRO)/tools/bin/elf2dol$(EXE_EXT)
endif
INCLUDE += -I. -I$(DEVKITPRO)/libogc/include -Iwii/libogc/include
INCLUDE += -I.
ifeq ($(EXTERNAL_LIBOGC), 1)
CFLAGS += -DEXTERNAL_LIBOGC
CXXFLAGS += -DEXTERNAL_LIBOGC
LIBDIRS += -L$(DEVKITPRO)/libogc/lib/wii
INCLUDE += -I$(DEVKITPRO)/libogc/include
else
CFLAGS += -DINTERNAL_LIBOGC
CXXFLAGS += -DINTERNAL_LIBOGC
LIBDIRS += -Lwii/libogc/libs/wii
INCLUDE += -Iwii/libogc/include
endif
ifeq ($(GX_PTHREAD_LEGACY), 1)
@@ -100,6 +103,10 @@ LIBS += -lwiiuse -lbte
ifeq ($(USBGECKO), 1)
LIBS += -ldb
endif
ifeq ($(HAVE_LOGGER), 1)
LIBS += -lbba
endif
LIBS += -logc
@@ -127,12 +134,25 @@ HAVE_REWIND := 1
HAVE_AUDIOMIXER := 1
HAVE_RWAV := 1
RARCH_CONSOLE = 1
HAVE_CHEATS := 1
HAVE_CORE_INFO_CACHE := 1
HAVE_MENU_COMMON := 1
HAVE_MENU := 1
HAVE_BUILTINZLIB := 1
HAVE_STATIC_AUDIO_FILTERS := 1
HAVE_STATIC_VIDEO_FILTERS := 1
#HAVE_LANGEXTRA := 1
HAVE_WIIUSB_HID := 1
HAVE_HID := 1
HAVE_RARCH_EXEC := 1
HAVE_CORE_INFO_CACHE := 1
HAVE_RSOUND := 0
HAVE_XMB := 0
HAVE_OZONE := 0
HAVE_RGUI := 1
HAVE_MATERIALUI := 0
CFLAGS += -DHAVE_SOCKET_LEGACY
APP_BOOTER_DIR = wii/app_booter
PLATOBJS := $(APP_BOOTER_DIR)/app_booter.binobj
@@ -141,19 +161,23 @@ ifeq ($(USBGECKO), 1)
CFLAGS += -DUSBGECKO
endif
HAVE_CHEATS := 1
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
INCLUDE += -I./libretro-common/include \
-Ideps \
-Ideps/stb
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
OBJ = griffin/griffin.o $(PLATOBJS)
OBJ = $(PLATOBJS) audio/drivers/gx_audio.o gfx/drivers/gx_gfx.o input/drivers/gx_input.o frontend/drivers/platform_gx.o input/drivers_joypad/gx_joypad.o memory/wii/mem2_manager.o gfx/drivers/gx_gfx_vi_encoder.o frontend/drivers/platform_wii.o input/drivers_hid/wiiusb_hid.o
ifeq ($(HAVE_GRIFFIN_CPP), 1)
OBJ += griffin/griffin_cpp.o
ifeq ($(EXTERNAL_LIBOGC), 0)
OBJ += wii/libogc/libfat/libfat.o wii/libogc/libfat/fatfile.o wii/libogc/libfat/file_allocation_table.o wii/libogc/libfat/cache.o wii/libogc/libfat/fatdir.o wii/libogc/libfat/partition.o wii/libogc/libfat/directory.o wii/libogc/libfat/filetime.o wii/libogc/libfat/disc.o
endif
include Makefile.common
CFLAGS += $(DEFINES) -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" \
-DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) \
ifeq ($(WANT_GLSLANG), 1)
OBJ += griffin/griffin_glslang.o
endif
@@ -163,28 +187,18 @@ ifeq ($(HAVE_LOGGER), 1)
CFLAGS += -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT)
endif
CFLAGS += -DHAVE_SOCKET_LEGACY
ifeq ($(HAVE_KERNEL_PRX), 1)
CFLAGS += -DHAVE_KERNEL_PRX
endif
ifeq ($(HAVE_WIIUSB_HID), 1)
CFLAGS += -DHAVE_WIIUSB_HID -DHAVE_HID
endif
ifeq ($(HAVE_LIBRETRODB), 1)
CFLAGS += -DHAVE_LIBRETRODB
CFLAGS += -DHAVE_WIIUSB_HID
endif
ifeq ($(BIG_STACK),1)
CFLAGS += -DBIG_STACK
endif
ifeq ($(HAVE_RJPEG), 1)
CFLAGS += -DHAVE_RJPEG
endif
ifeq ($(HAVE_FILE_LOGGER), 1)
CFLAGS += -DHAVE_FILE_LOGGER
endif
@@ -198,66 +212,10 @@ ifeq ($(HAVE_ZLIB), 1)
CFLAGS += -I./libretro-common/include/compat/zlib
endif
ifeq ($(HAVE_RPNG), 1)
CFLAGS += -DHAVE_RPNG
endif
ifeq ($(HAVE_RBMP), 1)
CFLAGS += -DHAVE_RBMP
endif
ifeq ($(HAVE_RTGA), 1)
CFLAGS += -DHAVE_RTGA
endif
ifeq ($(HAVE_IMAGEVIEWER), 1)
CFLAGS += -DHAVE_IMAGEVIEWER
endif
ifeq ($(HAVE_BSV_MOVIE), 1)
CFLAGS += -DHAVE_BSV_MOVIE
endif
ifeq ($(HAVE_RUNAHEAD), 1)
CFLAGS += -DHAVE_RUNAHEAD
endif
ifeq ($(HAVE_7ZIP), 1)
CFLAGS += -DHAVE_7ZIP -D_7ZIP_ST
endif
ifeq ($(HAVE_SCREENSHOTS), 1)
CFLAGS += -DHAVE_SCREENSHOTS
endif
ifeq ($(HAVE_REWIND), 1)
CFLAGS += -DHAVE_REWIND
endif
ifeq ($(HAVE_AUDIOMIXER), 1)
CFLAGS += -DHAVE_AUDIOMIXER
endif
ifeq ($(HAVE_RWAV), 1)
CFLAGS += -DHAVE_RWAV
endif
ifeq ($(HAVE_OVERLAY), 1)
CFLAGS += -DHAVE_OVERLAY
endif
ifeq ($(HAVE_VIDEO_LAYOUT), 1)
CFLAGS += -DHAVE_VIDEO_LAYOUT
endif
ifeq ($(HAVE_NETWORKING), 1)
CFLAGS += -DHAVE_NETWORKING
endif
ifeq ($(HAVE_NETPLAYDISCOVERY), 1)
CFLAGS += -DHAVE_NETPLAYDISCOVERY
endif
ifeq ($(RARCH_CONSOLE), 1)
CFLAGS += -DRARCH_CONSOLE
endif
@@ -268,50 +226,10 @@ endif
CFLAGS += -std=gnu99 -DHAVE_RGUI -DHAVE_MENU -DHAVE_GRIFFIN=1 -Wno-char-subscripts -DRARCH_INTERNAL
ifeq ($(HAVE_MATERIALUI), 1)
CFLAGS += -DHAVE_MATERIALUI
endif
ifeq ($(HAVE_XMB), 1)
CFLAGS += -DHAVE_XMB
endif
ifeq ($(HAVE_STB_FONT), 1)
CFLAGS += -DHAVE_STB_FONT
endif
ifeq ($(HAVE_LANGEXTRA), 1)
CFLAGS += -DHAVE_LANGEXTRA
endif
ifeq ($(HAVE_DSP_FILTER), 1)
CFLAGS += -DHAVE_DSP_FILTER
endif
ifeq ($(HAVE_VIDEO_FILTER), 1)
CFLAGS += -DHAVE_VIDEO_FILTER
endif
ifeq ($(HAVE_FILTERS_BUILTIN), 1)
CFLAGS += -DHAVE_FILTERS_BUILTIN
endif
ifeq ($(HAVE_THREADS), 1)
CFLAGS += -DHAVE_THREADS
endif
ifeq ($(HAVE_CONFIGFILE), 1)
CFLAGS += -DHAVE_CONFIGFILE
endif
ifeq ($(HAVE_PATCH), 1)
CFLAGS += -DHAVE_PATCH
endif
ifeq ($(HAVE_CHEATS), 1)
CFLAGS += -DHAVE_CHEATS
endif
ifeq ($(HAVE_RSOUND), 1)
CFLAGS += -DHAVE_RSOUND
endif
@@ -320,22 +238,10 @@ ifeq ($(HAVE_GETOPT_LONG), 1)
CFLAGS += -DHAVE_GETOPT_LONG=1
endif
ifeq ($(HAVE_DYLIB), 1)
CFLAGS += -DHAVE_DYLIB
endif
ifeq ($(HAVE_NETWORK_CMD), 1)
CFLAGS += -DHAVE_NETWORK_CMD
endif
ifeq ($(HAVE_COMMAND), 1)
CFLAGS += -DHAVE_COMMAND
endif
ifeq ($(HAVE_STDIN_CMD), 1)
CFLAGS += -DHAVE_STDIN_CMD
endif
ifeq ($(HAVE_DYNAMIC), 1)
CFLAGS += -DHAVE_DYNAMIC
endif
-7
View File
@@ -25,7 +25,6 @@ HAVE_MATERIALUI = 1
HAVE_DSP_FILTER = 1
HAVE_VIDEO_FILTER = 1
HAVE_7ZIP = 1
HAVE_PYTHON = 0
DYNAMIC = 1
HAVE_CORE_INFO_CACHE = 1
@@ -35,7 +34,6 @@ HAVE_WINMM = 1
HAVE_SDL := 0
HAVE_SDL2 := 0
HAVE_RSOUND := 0
HAVE_PYTHON := 0
HAVE_STB_FONT := 1
HAVE_FREETYPE := 1
@@ -84,11 +82,6 @@ RSOUND_CFLAGS := -DHAVE_RSOUND
RSOUND_LIBS := -lrsound
endif
ifeq ($(HAVE_PYTHON), 1)
PYTHON_LIBS := -lpython32
PYTHON_CFLAGS := -DHAVE_PYTHON -Ipython
endif
ifeq ($(HAVE_FFMPEG), 1)
AVCODEC_LIBS := -lavcodec
AVUTIL_LIBS := -lavutil
+2 -2
View File
@@ -76,11 +76,11 @@ In the end you should have this on your system:
gl3.h
gl3platform.h
To enable mali_fbdev you must configure RetroArch with --enable-gles and --enable-mali_fbdev.
To enable mali_fbdev you must configure RetroArch with --enable-opengles and --enable-mali_fbdev.
This is an example of what you would use on a CubieBoard2 for a lightweight RetroArch:
./configure --enable-gles --enable-mali_fbdev --disable-x11 --disable-sdl2 --enable-floathard --disable-ffmpeg --disable-netplay --enable-udev --disable-sdl --disable-pulse --disable-oss --disable-freetype --disable-7zip
./configure --enable-opengles --enable-mali_fbdev --disable-x11 --disable-sdl2 --enable-floathard --disable-ffmpeg --disable-netplay --enable-udev --disable-sdl --disable-pulse --disable-oss --disable-freetype --disable-7zip
NOTE: A TTY hack is used to auto-clean the console on exit, and the fbdev ioctls are used to retrieve
current video mode. Both things work good, but they are not exactly ideal solutions.
+9 -8
View File
@@ -33,12 +33,13 @@
#include "../audio_driver.h"
#include "../../verbosity.h"
#include "defines/cocoa_defines.h"
typedef struct coreaudio
{
slock_t *lock;
scond_t *cond;
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
ComponentInstance dev;
#else
AudioComponentInstance dev;
@@ -64,7 +65,7 @@ static void coreaudio_free(void *data)
if (dev->dev_alive)
{
AudioOutputUnitStop(dev->dev);
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
CloseComponent(dev->dev);
#else
AudioComponentInstanceDispose(dev->dev);
@@ -139,7 +140,7 @@ static void choose_output_device(coreaudio_t *dev, const char* device)
UInt32 size = 0;
propaddr.mSelector = kAudioHardwarePropertyDevices;
#if MAC_OS_X_VERSION_10_12
#if HAS_MACOSX_10_12
propaddr.mScope = kAudioObjectPropertyScopeOutput;
#else
propaddr.mScope = kAudioObjectPropertyScopeGlobal;
@@ -157,7 +158,7 @@ static void choose_output_device(coreaudio_t *dev, const char* device)
&propaddr, 0, 0, &size, devices) != noErr)
goto done;
#if MAC_OS_X_VERSION_10_12
#if HAS_MACOSX_10_12
#else
propaddr.mScope = kAudioDevicePropertyScopeOutput;
#endif
@@ -192,7 +193,7 @@ static void *coreaudio_init(const char *device,
size_t fifo_size;
UInt32 i_size;
AudioStreamBasicDescription real_desc;
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
Component comp;
#else
AudioComponent comp;
@@ -204,7 +205,7 @@ static void *coreaudio_init(const char *device,
AudioStreamBasicDescription stream_desc = {0};
bool component_unavailable = false;
static bool session_initialized = false;
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
ComponentDescription desc = {0};
#else
AudioComponentDescription desc = {0};
@@ -238,7 +239,7 @@ static void *coreaudio_init(const char *device,
#endif
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
comp = FindNextComponent(NULL, &desc);
#else
comp = AudioComponentFindNext(NULL, &desc);
@@ -246,7 +247,7 @@ static void *coreaudio_init(const char *device,
if (!comp)
goto error;
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if !HAS_MACOSX_10_12
component_unavailable = (OpenAComponent(comp, &dev->dev) != noErr);
#else
component_unavailable = (AudioComponentInstanceNew(comp, &dev->dev) != noErr);
+14 -9
View File
@@ -136,8 +136,8 @@ static void dsound_thread(void *data)
static DWORD CALLBACK dsound_thread(PVOID data)
#endif
{
DWORD write_ptr;
dsound_t *ds = (dsound_t*)data;
DWORD write_ptr = 0;
dsound_t *ds = (dsound_t*)data;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
@@ -315,15 +315,20 @@ static BOOL CALLBACK enumerate_cb(LPGUID guid,
if (guid)
{
unsigned i;
LPGUID guid_copy = (LPGUID)malloc(sizeof(GUID) * 1);
guid_copy->Data1 = guid->Data1;
guid_copy->Data2 = guid->Data2;
guid_copy->Data3 = guid->Data3;
for (i = 0; i < 8; i++)
guid_copy->Data4[i] = guid->Data4[i];
list->elems[list->size-1].userdata = guid_copy;
if (guid_copy)
{
unsigned i;
guid_copy->Data1 = guid->Data1;
guid_copy->Data2 = guid->Data2;
guid_copy->Data3 = guid->Data3;
for (i = 0; i < 8; i++)
guid_copy->Data4[i] = guid->Data4[i];
list->elems[list->size - 1].userdata = guid_copy;
}
}
return TRUE;
+33 -25
View File
@@ -54,7 +54,7 @@ typedef struct psp_audio
SceUID thread;
int rate;
int port;
volatile uint16_t read_pos;
volatile uint16_t write_pos;
@@ -67,22 +67,27 @@ typedef struct psp_audio
#define AUDIO_BUFFER_SIZE (1u<<13u)
#define AUDIO_BUFFER_SIZE_MASK (AUDIO_BUFFER_SIZE-1)
/* Return port used */
static int configureAudio(unsigned rate) {
int port;
#if defined(VITA)
port = sceAudioOutOpenPort(
SCE_AUDIO_OUT_PORT_TYPE_MAIN, AUDIO_OUT_COUNT,
rate, SCE_AUDIO_OUT_MODE_STEREO);
#elif defined(ORBIS)
port = sceAudioOutOpen(0xff,
SCE_AUDIO_OUT_PORT_TYPE_MAIN, 0, AUDIO_OUT_COUNT,
rate, SCE_AUDIO_OUT_MODE_STEREO);
#else
port = sceAudioSRCChReserve(AUDIO_OUT_COUNT, rate, 2);
#endif
return port;
}
static void audioMainLoop(void *data)
{
psp_audio_t* psp = (psp_audio_t*)data;
#if defined(VITA)
int port = sceAudioOutOpenPort(
SCE_AUDIO_OUT_PORT_TYPE_MAIN, AUDIO_OUT_COUNT,
psp->rate, SCE_AUDIO_OUT_MODE_STEREO);
#elif defined(ORBIS)
int port = sceAudioOutOpen(0xff,
SCE_AUDIO_OUT_PORT_TYPE_MAIN, 0, AUDIO_OUT_COUNT,
psp->rate, SCE_AUDIO_OUT_MODE_STEREO);
#else
sceAudioSRCChReserve(AUDIO_OUT_COUNT, psp->rate, 2);
#endif
while (psp->running)
{
bool cond = false;
@@ -107,7 +112,7 @@ static void audioMainLoop(void *data)
slock_unlock(psp->cond_lock);
#if defined(VITA) || defined(ORBIS)
sceAudioOutOutput(port,
sceAudioOutOutput(psp->port,
cond ? (psp->zeroBuffer)
: (psp->buffer + read_pos_2));
#else
@@ -116,14 +121,6 @@ static void audioMainLoop(void *data)
#endif
}
#if defined(VITA)
sceAudioOutReleasePort(port);
#elif defined(ORBIS)
sceAudioOutClose(port);
#else
sceAudioSRCChRelease();
#endif
return;
}
@@ -137,8 +134,9 @@ static void *psp_audio_init(const char *device,
if (!psp)
return NULL;
(void)device;
(void)latency;
int port = configureAudio(rate);
if (port < 0)
return NULL;
#ifdef ORBIS
psp->buffer = (uint32_t*)
@@ -161,7 +159,7 @@ static void *psp_audio_init(const char *device,
psp->read_pos = 0;
psp->write_pos = 0;
psp->rate = rate;
psp->port = port;
psp->fifo_lock = slock_new();
psp->cond_lock = slock_new();
@@ -197,7 +195,17 @@ static void psp_audio_free(void *data)
free(psp->buffer);
psp->worker_thread = NULL;
free(psp->zeroBuffer);
#if defined(VITA)
sceAudioOutReleasePort(psp->port);
#elif defined(ORBIS)
sceAudioOutClose(psp->port);
#else
sceAudioSRCChRelease();
#endif
free(psp);
}
static ssize_t psp_audio_write(void *data, const void *buf, size_t size)
@@ -9,7 +9,6 @@ PSP_EXPORT_VAR_HASH(module_info)
PSP_EXPORT_END
PSP_EXPORT_START(kernel_functions, 0, 0x4001)
PSP_EXPORT_FUNC(read_system_buttons)
PSP_EXPORT_FUNC(exitspawn_kernel)
PSP_EXPORT_END
@@ -1,49 +1,17 @@
#include <stdio.h>
#include <string.h>
#include <pspdebug.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <psploadexec_kernel.h>
#include <pspthreadman_kernel.h>
PSP_MODULE_INFO("kernel_functions", PSP_MODULE_KERNEL, 0, 0);
PSP_MAIN_THREAD_ATTR(0);
static volatile int thread_active;
static unsigned int buttons;
static SceUID main_thread_id;
static int main_thread(SceSize args, void *argp)
{
SceCtrlData paddata;
thread_active = 1;
while (thread_active)
{
sceCtrlPeekBufferPositive(&paddata, 1);
buttons = paddata.Buttons;
sceKernelDelayThread(1000000/60);
}
sceKernelExitThread(0);
return 0;
}
unsigned int read_system_buttons(void)
{
return buttons;
}
void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
{
int k1;
struct SceKernelLoadExecVSHParam game_param;
thread_active = 0;
memset(&game_param,0,sizeof(game_param));
game_param.size = sizeof(game_param);
@@ -57,34 +25,16 @@ void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
game_param.unk5 = 0x10000;
k1 = pspSdkSetK1(0);
#if 0
sceKernelSuspendAllUserThreads();
#endif
sceKernelLoadExecVSHMs2(fileName, &game_param);
pspSdkSetK1(k1);
}
int module_start(SceSize args, void *argp)
{
(void)args;
(void)argp;
buttons = 0;
thread_active = 0;
main_thread_id = sceKernelCreateThread("main Thread", main_thread, 0x11, 0x200, 0, NULL);
if (main_thread >= 0)
sceKernelStartThread(main_thread_id, 0, 0);
return 0;
}
int module_stop(void)
{
if (main_thread_id >= 0)
{
thread_active = 0;
sceKernelWaitThreadEnd(main_thread_id, NULL);
}
return 0;
}
+2 -3
View File
@@ -43,7 +43,6 @@ void _init_vita_heap(void) {
if (_newlib_vm_memblock < 0){
//sceClibPrintf("sceKernelAllocMemBlockForVM failed\n");
goto failure;
}
}else{
_newlib_vm_memblock = 0;
@@ -99,8 +98,8 @@ void _free_vita_heap(void) {
// Free the heap memblock to avoid memory leakage.
sceKernelFreeMemBlock(_newlib_heap_memblock);
if(_newlib_vm_memblock)
sceKernelFreeMemBlock(_newlib_vm_memblock);
if (_newlib_vm_memblock > 0)
sceKernelFreeMemBlock(_newlib_vm_memblock);
_newlib_vm_memblock = 0;
_newlib_heap_memblock = 0;
+4
View File
@@ -304,6 +304,8 @@ static void cheat_manager_free(void)
free(cheat_st->cheats[i].desc);
if (cheat_st->cheats[i].code)
free(cheat_st->cheats[i].code);
cheat_st->cheats[i].desc = NULL;
cheat_st->cheats[i].code = NULL;
}
free(cheat_st->cheats);
@@ -560,6 +562,8 @@ bool cheat_manager_realloc(unsigned new_size, unsigned default_handler)
free(cheat_st->cheats[i].code);
if (cheat_st->cheats[i].desc)
free(cheat_st->cheats[i].desc);
cheat_st->cheats[i].code = NULL;
cheat_st->cheats[i].desc = NULL;
}
val = (struct item_cheat*)
+229 -67
View File
@@ -65,12 +65,14 @@
#include "../performance_counters.h"
#include "../msg_hash.h"
#include "../retroarch.h"
#include "../runtime_file.h"
#include "../core.h"
#include "../core_option_manager.h"
#include "../tasks/tasks_internal.h"
#include "../deps/rcheevos/include/rc_runtime.h"
#include "../deps/rcheevos/include/rc_runtime_types.h"
#include "../deps/rcheevos/include/rc_hash.h"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
@@ -85,6 +87,7 @@ static rcheevos_locals_t rcheevos_locals =
#ifdef HAVE_THREADS
CMD_EVENT_NONE, /* queued_command */
#endif
"", /* displayname */
"", /* username */
"", /* token */
"", /* user_agent_prefix */
@@ -662,10 +665,10 @@ bool rcheevos_unload(void)
rcheevos_locals.hardcore_active = false;
}
while (rcheevos_locals.game.hashes != NULL)
while (rcheevos_locals.game.hashes)
{
rcheevos_hash_entry_t* hash_entry = rcheevos_locals.game.hashes;
rcheevos_locals.game.hashes = hash_entry->next;
rcheevos_locals.game.hashes = hash_entry->next;
free(hash_entry);
}
@@ -861,6 +864,9 @@ static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals)
runloop_msg_queue_push(msg, 0, 3 * 60, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* disable slowdown */
runloop_state_get_ptr()->slowmotion = false;
/* Reactivate leaderboards */
if (locals->leaderboards_enabled)
rcheevos_activate_leaderboards();
@@ -922,7 +928,7 @@ static void rcheevos_toggle_hardcore_active(rcheevos_locals_t* locals)
void rcheevos_toggle_hardcore_paused(void)
{
settings_t* settings = config_get_ptr();
/* if hardcore mode is not enabled, we can't toggle it */
/* if hardcore mode is not enabled, we can't toggle whether its active */
if (settings->bools.cheevos_hardcore_mode_enable)
rcheevos_toggle_hardcore_active(&rcheevos_locals);
}
@@ -1144,14 +1150,67 @@ bool rcheevos_get_serialized_data(void* buffer)
bool rcheevos_set_serialized_data(void* buffer)
{
if (rcheevos_locals.loaded)
if (rcheevos_locals.loaded && buffer)
{
if (buffer && rc_runtime_deserialize_progress(
&rcheevos_locals.runtime,
(const unsigned char*)buffer, NULL) == RC_OK)
return true;
const int result = rc_runtime_deserialize_progress(
&rcheevos_locals.runtime, (const unsigned char*)buffer, NULL);
rc_runtime_reset(&rcheevos_locals.runtime);
#if defined(HAVE_GFX_WIDGETS)
if (gfx_widgets_ready() && rcheevos_is_player_active())
{
settings_t* settings = config_get_ptr();
if (rcheevos_locals.leaderboard_trackers)
{
unsigned i;
rc_runtime_lboard_t* lboard = rcheevos_locals.runtime.lboards;
for (i = 0; i < rcheevos_locals.runtime.lboard_count; ++i, ++lboard)
{
if (!lboard->lboard)
continue;
if (lboard->lboard->state == RC_LBOARD_STATE_STARTED)
{
rcheevos_ralboard_t* ralboard = rcheevos_find_lboard(lboard->id);
if (ralboard != NULL)
{
char value[32];
rc_runtime_format_lboard_value(value, sizeof(value), lboard->value, ralboard->format);
gfx_widgets_set_leaderboard_display(lboard->id, value);
}
}
else
{
gfx_widgets_set_leaderboard_display(lboard->id, NULL);
}
}
}
if (settings->bools.cheevos_challenge_indicators)
{
unsigned i;
rc_runtime_trigger_t* cheevo = rcheevos_locals.runtime.triggers;
for (i = 0; i < rcheevos_locals.runtime.trigger_count; ++i, ++cheevo)
{
if (!cheevo->trigger)
continue;
if (cheevo->trigger->state == RC_TRIGGER_STATE_PRIMED)
{
rcheevos_racheevo_t* racheevo = rcheevos_find_cheevo(cheevo->id);
if (racheevo != NULL)
gfx_widgets_set_challenge_display(racheevo->id, racheevo->badge);
}
else
{
gfx_widgets_set_challenge_display(cheevo->id, NULL);
}
}
}
}
#endif
return (result == RC_OK);
}
return false;
@@ -1206,7 +1265,8 @@ static void rc_hash_handle_file_close(void* file_handle)
CHEEVOS_FREE(file_handle);
}
static void* rc_hash_handle_cd_open_track(
#ifdef HAVE_CHD
static void* rc_hash_handle_chd_open_track(
const char* path, uint32_t track)
{
cdfs_track_t* cdfs_track;
@@ -1218,27 +1278,11 @@ static void* rc_hash_handle_cd_open_track(
break;
case RC_HASH_CDTRACK_LAST:
#ifdef HAVE_CHD
if (string_is_equal_noncase(path_get_extension(path), "chd"))
{
cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_LAST);
break;
}
#endif
CHEEVOS_LOG(RCHEEVOS_TAG "Last track only supported for CHD\n");
cdfs_track = NULL;
cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_LAST);
break;
case RC_HASH_CDTRACK_LARGEST:
#ifdef HAVE_CHD
if (string_is_equal_noncase(path_get_extension(path), "chd"))
{
cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_PRIMARY);
break;
}
#endif
CHEEVOS_LOG(RCHEEVOS_TAG "Largest track only supported for CHD, using first data track\n");
cdfs_track = cdfs_open_data_track(path);
cdfs_track = cdfs_open_track(path, CHDSTREAM_TRACK_PRIMARY);
break;
default:
@@ -1259,17 +1303,29 @@ static void* rc_hash_handle_cd_open_track(
return NULL;
}
static size_t rc_hash_handle_cd_read_sector(
static size_t rc_hash_handle_chd_read_sector(
void* track_handle, uint32_t sector,
void* buffer, size_t requested_bytes)
{
cdfs_file_t* file = (cdfs_file_t*)track_handle;
uint32_t track_sectors = cdfs_get_num_sectors(file);
sector -= cdfs_get_first_sector(file);
if (sector >= track_sectors)
return 0;
cdfs_seek_sector(file, sector);
return cdfs_read_file(file, buffer, requested_bytes);
}
static void rc_hash_handle_cd_close_track(void* track_handle)
static uint32_t rc_hash_handle_chd_first_track_sector(
void* track_handle)
{
cdfs_file_t* file = (cdfs_file_t*)track_handle;
return cdfs_get_first_sector(file);
}
static void rc_hash_handle_chd_close_track(void* track_handle)
{
cdfs_file_t* file = (cdfs_file_t*)track_handle;
if (file)
@@ -1280,8 +1336,109 @@ static void rc_hash_handle_cd_close_track(void* track_handle)
}
}
#endif
static void rc_hash_reset_cdreader_hooks(void);
static void* rc_hash_handle_cd_open_track(
const char* path, uint32_t track)
{
struct rc_hash_cdreader cdreader;
if (string_is_equal_noncase(path_get_extension(path), "chd"))
{
#ifdef HAVE_CHD
/* special handlers for CHD file */
memset(&cdreader, 0, sizeof(cdreader));
cdreader.open_track = rc_hash_handle_cd_open_track;
cdreader.read_sector = rc_hash_handle_chd_read_sector;
cdreader.close_track = rc_hash_handle_chd_close_track;
cdreader.first_track_sector = rc_hash_handle_chd_first_track_sector;
rc_hash_init_custom_cdreader(&cdreader);
return rc_hash_handle_chd_open_track(path, track);
#else
CHEEVOS_LOG(RCHEEVOS_TAG "Cannot generate hash from CHD without HAVE_CHD compile flag\n");
return NULL;
#endif
}
else
{
/* not a CHD file, use the default handlers */
rc_hash_get_default_cdreader(&cdreader);
rc_hash_reset_cdreader_hooks();
return cdreader.open_track(path, track);
}
}
static void rc_hash_reset_cdreader_hooks()
{
struct rc_hash_cdreader cdreader;
rc_hash_get_default_cdreader(&cdreader);
cdreader.open_track = rc_hash_handle_cd_open_track;
rc_hash_init_custom_cdreader(&cdreader);
}
/* end hooks */
void rcheevos_show_mastery_placard()
{
const settings_t* settings = config_get_ptr();
char title[256];
if (rcheevos_locals.game.mastery_placard_shown)
return;
rcheevos_locals.game.mastery_placard_shown = true;
snprintf(title, sizeof(title),
msg_hash_to_str(rcheevos_locals.hardcore_active ? MSG_CHEEVOS_MASTERED_GAME : MSG_CHEEVOS_COMPLETED_GAME),
rcheevos_locals.game.title);
title[sizeof(title) - 1] = '\0';
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", title);
#if defined (HAVE_GFX_WIDGETS)
if (gfx_widgets_ready())
{
const bool content_runtime_log = settings->bools.content_runtime_log;
const bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate;
char msg[128];
size_t len;
len = snprintf(msg, sizeof(msg), "%s", rcheevos_locals.displayname);
if (len < sizeof(msg) - 12 &&
(content_runtime_log || content_runtime_log_aggr))
{
const char* content_path = path_get(RARCH_PATH_CONTENT);
const char* core_path = path_get(RARCH_PATH_CORE);
runtime_log_t* runtime_log = runtime_log_init(
content_path, core_path,
settings->paths.directory_runtime_log,
settings->paths.directory_playlist,
!content_runtime_log_aggr);
if (runtime_log)
{
const runloop_state_t* runloop_state = runloop_state_get_ptr();
runtime_log_add_runtime_usec(runtime_log,
runloop_state->core_runtime_usec);
len += snprintf(msg + len, sizeof(msg) - len, " | ");
runtime_log_get_runtime_str(runtime_log, msg + len, sizeof(msg) - len);
msg[sizeof(msg) - 1] = '\0';
free(runtime_log);
}
}
gfx_widgets_push_achievement(title, msg, rcheevos_locals.game.badge_name);
}
else
#endif
runloop_msg_queue_push(title, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
static void rcheevos_show_game_placard()
{
char msg[256];
@@ -1476,7 +1633,7 @@ static void rcheevos_fetch_game_data(void)
return;
}
if (rcheevos_locals.game.id == 0)
if (rcheevos_locals.game.id <= 0)
{
const settings_t* settings = config_get_ptr();
if (settings->bools.cheevos_verbose_enable)
@@ -1577,18 +1734,36 @@ static void rcheevos_identify_game_callback(void* userdata)
static bool rcheevos_identify_game(const struct retro_game_info* info)
{
struct rcheevos_identify_game_data* data;
struct rc_hash_filereader filereader;
struct rc_hash_iterator iterator;
size_t len;
char hash[33];
#ifndef HAVE_CHD
if (string_is_equal_noncase(path_get_extension(info->path), "chd"))
{
CHEEVOS_LOG(RCHEEVOS_TAG "CHD not supported without HAVE_CHD compile flag\n");
return false;
}
#ifndef DEBUG
settings_t* settings = config_get_ptr();
#endif
/* provide hooks for reading files */
memset(&filereader, 0, sizeof(filereader));
filereader.open = rc_hash_handle_file_open;
filereader.seek = rc_hash_handle_file_seek;
filereader.tell = rc_hash_handle_file_tell;
filereader.read = rc_hash_handle_file_read;
filereader.close = rc_hash_handle_file_close;
rc_hash_init_custom_filereader(&filereader);
rc_hash_init_error_message_callback(rcheevos_handle_log_message);
#ifndef DEBUG
/* in DEBUG mode, always initialize the verbose message handler */
if (settings->bools.cheevos_verbose_enable)
#endif
{
rc_hash_init_verbose_message_callback(rcheevos_handle_log_message);
}
rc_hash_reset_cdreader_hooks();
/* fetch the first hash */
rc_hash_initialize_iterator(&iterator,
info->path, (uint8_t*)info->data, info->size);
if (!rc_hash_iterate(hash, &iterator))
@@ -1606,6 +1781,7 @@ static bool rcheevos_identify_game(const struct retro_game_info* info)
if (iterator.consoles[iterator.index] == 0)
{
/* no more potential matches, just try the one hash */
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
rcheevos_client_identify_game(hash,
rcheevos_identify_game_callback, NULL);
return true;
@@ -1638,6 +1814,8 @@ static bool rcheevos_identify_game(const struct retro_game_info* info)
}
memcpy(&data->iterator, &iterator, sizeof(iterator));
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
rcheevos_client_identify_game(hash,
rcheevos_identify_game_callback, data);
return true;
@@ -1653,7 +1831,7 @@ static void rcheevos_login_callback(void* userdata)
char msg[256];
snprintf(msg, sizeof(msg),
"RetroAchievements: Logged in as \"%s\".",
rcheevos_locals.username);
rcheevos_locals.displayname);
runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
@@ -1706,8 +1884,6 @@ bool rcheevos_load_aborted(void)
bool rcheevos_load(const void *data)
{
struct rc_hash_cdreader cdreader;
struct rc_hash_filereader filereader;
const struct retro_game_info *info = (const struct retro_game_info*)
data;
settings_t *settings = config_get_ptr();
@@ -1720,6 +1896,7 @@ bool rcheevos_load(const void *data)
rcheevos_locals.loaded = false;
rcheevos_locals.game.id = -1;
rcheevos_locals.game.console_id = 0;
rcheevos_locals.game.mastery_placard_shown = false;
#ifdef HAVE_THREADS
rcheevos_locals.queued_command = CMD_EVENT_NONE;
#endif
@@ -1734,6 +1911,16 @@ bool rcheevos_load(const void *data)
return false;
}
if (string_is_empty(settings->arrays.cheevos_username))
{
CHEEVOS_LOG(RCHEEVOS_TAG "Cannot login (no username)\n");
runloop_msg_queue_push("Missing RetroAchievements account information.", 0, 5 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
rcheevos_locals.game.id = 0;
rcheevos_pause_hardcore();
return false;
}
#ifdef HAVE_THREADS
if (!rcheevos_locals.load_info.request_lock)
rcheevos_locals.load_info.request_lock = slock_new();
@@ -1747,31 +1934,6 @@ bool rcheevos_load(const void *data)
rcheevos_validate_config_settings();
rcheevos_leaderboards_enabled_changed();
/* provide hooks for reading files */
memset(&filereader, 0, sizeof(filereader));
filereader.open = rc_hash_handle_file_open;
filereader.seek = rc_hash_handle_file_seek;
filereader.tell = rc_hash_handle_file_tell;
filereader.read = rc_hash_handle_file_read;
filereader.close = rc_hash_handle_file_close;
rc_hash_init_custom_filereader(&filereader);
memset(&cdreader, 0, sizeof(cdreader));
cdreader.open_track = rc_hash_handle_cd_open_track;
cdreader.read_sector = rc_hash_handle_cd_read_sector;
cdreader.close_track = rc_hash_handle_cd_close_track;
rc_hash_init_custom_cdreader(&cdreader);
rc_hash_init_error_message_callback(rcheevos_handle_log_message);
#ifndef DEBUG
/* in DEBUG mode, always initialize the verbose message handler */
if (settings->bools.cheevos_verbose_enable)
#endif
{
rc_hash_init_verbose_message_callback(rcheevos_handle_log_message);
}
/* Refresh the user agent in case it's not set or has changed */
rcheevos_client_initialize();
rcheevos_get_user_agent(&rcheevos_locals,
@@ -1841,7 +2003,7 @@ bool rcheevos_load(const void *data)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Cannot login %s (no password or token)\n",
settings->arrays.cheevos_username);
runloop_msg_queue_push("Error logging in: No password provided", 0, 5 * 60, false, NULL,
runloop_msg_queue_push("No password provided for RetroAchievements account", 0, 5 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
rcheevos_unload();
return false;
+10 -2
View File
@@ -643,7 +643,9 @@ static void rcheevos_async_login_callback(
settings->arrays.cheevos_password[0] = '\0';
CHEEVOS_LOG(RCHEEVOS_TAG "%s logged in successfully\n",
api_response.username);
api_response.display_name);
strlcpy(rcheevos_locals->displayname, api_response.display_name,
sizeof(rcheevos_locals->displayname));
strlcpy(rcheevos_locals->username, api_response.username,
sizeof(rcheevos_locals->username));
strlcpy(rcheevos_locals->token, api_response.api_token,
@@ -746,7 +748,6 @@ void rcheevos_client_identify_game(const char* hash,
request->callback = callback;
request->callback_data = userdata;
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
rcheevos_async_begin_request(request, result,
rcheevos_async_resolve_hash_callback,
CHEEVOS_ASYNC_RESOLVE_HASH, 0,
@@ -1098,6 +1099,10 @@ static void rcheevos_async_fetch_game_data_callback(
"i%s", runtime_data->game_data.image_name);
rcheevos_client_fetch_game_badge(runtime_data->game_data.image_name, runtime_data);
}
else
{
rcheevos_unload();
}
}
void rcheevos_client_initialize_runtime(unsigned game_id,
@@ -1742,6 +1747,9 @@ static void rcheevos_async_award_achievement_callback(
CHEEVOS_LOG(RCHEEVOS_TAG "Achievement %u: %s\n",
request->id, api_response.response.error_message);
}
if (api_response.achievements_remaining == 0)
rcheevos_show_mastery_placard();
}
rc_api_destroy_award_achievement_response(&api_response);
+4
View File
@@ -135,6 +135,7 @@ typedef struct rcheevos_game_info_t
char* title;
char badge_name[16];
char* hash;
bool mastery_placard_shown;
rcheevos_hash_entry_t* hashes;
@@ -168,6 +169,7 @@ typedef struct rcheevos_locals_t
enum event_command queued_command; /* action queued by background thread to be run on main thread */
#endif
char displayname[32]; /* name to display in messages */
char username[32]; /* case-corrected username */
char token[32]; /* user's session token */
char user_agent_prefix[128]; /* RetroArch/OS version information */
@@ -194,6 +196,8 @@ void rcheevos_begin_load_state(enum rcheevos_load_state state);
int rcheevos_end_load_state(void);
bool rcheevos_load_aborted(void);
void rcheevos_show_mastery_placard(void);
#ifdef HAVE_THREADS
#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0)
#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0)
+10 -7
View File
@@ -116,9 +116,12 @@ bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
if (cheevo)
{
if (cheevo->menu_progress)
snprintf(buffer, len, "%s - %d%%",
msg_hash_to_str(menuitem->state_label_idx),
cheevo->menu_progress);
{
const int written = snprintf(buffer, len, "%s - ",
msg_hash_to_str(menuitem->state_label_idx));
if (len - written > 0)
rc_runtime_format_achievement_measured(&rcheevos_locals->runtime, cheevo->id, buffer + written, len - written);
}
else
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), len);
@@ -398,7 +401,7 @@ void rcheevos_menu_populate_hardcore_pause_submenu(void* data)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0);
menu_entries_append_enum(info->list,
@@ -411,7 +414,7 @@ void rcheevos_menu_populate_hardcore_pause_submenu(void* data)
{
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0);
menu_entries_append_enum(info->list,
@@ -448,13 +451,13 @@ void rcheevos_menu_populate(void* data)
if (rcheevos_locals->hardcore_active)
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
else
menu_entries_append_enum(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
}
+54 -7
View File
@@ -96,6 +96,8 @@ static bool command_get_arg(const char *tok,
if (str == tok)
{
const char *argument = str + strlen(action_map[i].str);
if (!argument)
return false;
if (*argument != ' ' && *argument != '\0')
return false;
@@ -334,6 +336,14 @@ command_t* command_stdin_new(void)
cmd = (command_t*)calloc(1, sizeof(command_t));
stdincmd = (command_stdin_t*)calloc(1, sizeof(command_stdin_t));
if (!cmd)
return NULL;
if (!stdincmd)
{
free(cmd);
return NULL;
}
cmd->userptr = stdincmd;
cmd->poll = command_stdin_poll;
cmd->replier = stdin_command_reply;
@@ -683,7 +693,7 @@ bool command_version(command_t *cmd, const char* arg)
return true;
}
static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned address)
static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned address, size_t* offset)
{
const rarch_memory_descriptor_t* desc = mmap->descriptors;
const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
@@ -694,15 +704,37 @@ static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarc
{
/* if select is 0, attempt to explicitly match the address */
if (address >= desc->core.start && address < desc->core.start + desc->core.len)
{
*offset = address - desc->core.start;
return desc;
}
}
else
{
/* otherwise, attempt to match the address by matching the select bits */
if (((desc->core.start ^ address) & desc->core.select) == 0)
{
/* adjust the address to the start of the descriptor */
unsigned desc_offset = address - (unsigned)desc->core.start;
/* address is unsigned. we only need that much of the disconnect mask */
unsigned mask = (unsigned)desc->core.disconnect;
/* this magic logic is copied from mmap_reduce. it removes any bits from
* address that are non-zero in the disconnect field. bits above the
* removed bits are shifted down to fill the gap. */
while (mask)
{
const unsigned tmp = (mask - 1) & ~mask;
desc_offset = (desc_offset & tmp) | ((desc_offset >> 1) & ~tmp);
mask = (mask & (mask - 1)) >> 1;
}
/* we've calculated the actual offset of the data within the descriptor */
*offset = desc_offset;
/* sanity check - make sure the descriptor is large enough to hold the target address */
if (address - desc->core.start < desc->core.len)
if (desc_offset < desc->core.len)
return desc;
}
}
@@ -723,7 +755,8 @@ uint8_t *command_memory_get_pointer(
strlcpy(reply_at, " -1 no memory map defined\n", len);
else
{
const rarch_memory_descriptor_t* desc = command_memory_get_descriptor(&system->mmaps, address);
size_t offset;
const rarch_memory_descriptor_t* desc = command_memory_get_descriptor(&system->mmaps, address, &offset);
if (!desc)
strlcpy(reply_at, " -1 no descriptor for address\n", len);
else if (!desc->core.ptr)
@@ -732,7 +765,6 @@ uint8_t *command_memory_get_pointer(
strlcpy(reply_at, " -1 descriptor data is readonly\n", len);
else
{
const size_t offset = address - desc->core.start;
*max_bytes = (desc->core.len - offset);
return (uint8_t*)desc->core.ptr + desc->core.offset + offset;
}
@@ -1088,6 +1120,8 @@ bool command_event_save_auto_state(
return false;
if (current_core_type == CORE_TYPE_DUMMY)
return false;
if (!core_info_current_supports_savestate())
return false;
if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))))
return false;
@@ -1148,6 +1182,9 @@ bool command_event_load_entry_state(void)
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool ret = false;
if (!core_info_current_supports_savestate())
return false;
#ifdef HAVE_CHEEVOS
if (rcheevos_hardcore_active())
return false;
@@ -1187,6 +1224,10 @@ void command_event_load_auto_state(void)
char savestate_name_auto[PATH_MAX_LENGTH];
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool ret = false;
if (!core_info_current_supports_savestate())
return;
#ifdef HAVE_CHEEVOS
if (rcheevos_hardcore_active())
return;
@@ -1551,16 +1592,22 @@ bool command_event_main_state(unsigned cmd)
char msg[128];
char state_path[16384];
settings_t *settings = config_get_ptr();
bool savestates_enabled = core_info_current_supports_savestate();
bool ret = false;
bool push_msg = true;
state_path[0] = msg[0] = '\0';
retroarch_get_current_savestate_path(state_path, sizeof(state_path));
if (savestates_enabled)
{
retroarch_get_current_savestate_path(state_path,
sizeof(state_path));
core_serialize_size(&info);
core_serialize_size(&info);
savestates_enabled = (info.size > 0);
}
if (info.size)
if (savestates_enabled)
{
switch (cmd)
{
+2
View File
@@ -74,6 +74,7 @@ enum event_command
CMD_EVENT_RESET,
CMD_EVENT_SET_PER_GAME_RESOLUTION,
CMD_EVENT_SET_FRAME_LIMIT,
CMD_EVENT_VRR_RUNLOOP_TOGGLE,
/* Loads core. */
CMD_EVENT_LOAD_CORE,
CMD_EVENT_LOAD_CORE_PERSIST,
@@ -442,6 +443,7 @@ static const struct cmd_map map[] = {
{ "FAST_FORWARD_HOLD", RARCH_FAST_FORWARD_HOLD_KEY },
{ "SLOWMOTION", RARCH_SLOWMOTION_KEY },
{ "SLOWMOTION_HOLD", RARCH_SLOWMOTION_HOLD_KEY },
{ "VRR_RUNLOOP_TOGGLE", RARCH_VRR_RUNLOOP_TOGGLE },
{ "LOAD_STATE", RARCH_LOAD_STATE_KEY },
{ "SAVE_STATE", RARCH_SAVE_STATE_KEY },
{ "FULLSCREEN_TOGGLE", RARCH_FULLSCREEN_TOGGLE_KEY },
+22 -4
View File
@@ -558,6 +558,7 @@
#define DEFAULT_OZONE_TRUNCATE_PLAYLIST_NAME true
#define DEFAULT_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME true
#define DEFAULT_OZONE_SCROLL_CONTENT_METADATA false
#define DEFAULT_OZONE_THUMBNAIL_SCALE_FACTOR 1.0f
#endif
#define DEFAULT_SETTINGS_SHOW_DRIVERS true
@@ -666,6 +667,9 @@ static const bool menu_show_core_updater = false;
#else
static const bool menu_show_core_updater = true;
#endif
#ifdef HAVE_MIST
static const bool menu_show_core_manager_steam = true;
#endif
static const bool menu_show_legacy_thumbnail_updater = false;
static const bool menu_show_sublabels = true;
static const bool menu_dynamic_wallpaper_enable = true;
@@ -730,10 +734,12 @@ static const bool content_show_playlists = true;
#if defined(HAVE_LIBRETRODB)
#define DEFAULT_MENU_CONTENT_SHOW_EXPLORE true
#endif
#define DEFAULT_MENU_CONTENT_SHOW_CONTENTLESS_CORES MENU_CONTENTLESS_CORES_DISPLAY_SINGLE_PURPOSE
#ifdef HAVE_XMB
#define DEFAULT_XMB_ANIMATION 0
#define DEFAULT_XMB_VERTICAL_FADE_FACTOR 100
#define DEFAULT_XMB_TITLE_MARGIN 5
static const unsigned xmb_alpha_factor = 75;
static const unsigned menu_font_color_red = 255;
@@ -762,7 +768,7 @@ static const float menu_footer_opacity = 1.000;
static const float menu_header_opacity = 1.000;
#if defined(HAVE_OPENGLES2) || (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if defined(HAVE_OPENGLES2) || (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
#define DEFAULT_MENU_SHADER_PIPELINE 1
#else
#define DEFAULT_MENU_SHADER_PIPELINE 2
@@ -850,7 +856,7 @@ static const unsigned input_backtouch_toggle = false;
#define DEFAULT_OVERLAY_SHOW_INPUTS_PORT 0
#if defined(ANDROID) || defined(_WIN32)
#if defined(ANDROID) || defined(_WIN32) || defined(HAVE_STEAM)
#define DEFAULT_MENU_SWAP_OK_CANCEL_BUTTONS true
#else
#define DEFAULT_MENU_SWAP_OK_CANCEL_BUTTONS false
@@ -944,12 +950,20 @@ static const float message_bgcolor_opacity = 1.0f;
#define DEFAULT_ALLOW_ROTATE true
#if defined(_3DS)
/* Enable New3DS clock and L2 cache */
static const bool new3ds_speedup_enable = true;
/* Enable bottom LCD screen */
static const bool video_3ds_lcd_bottom = true;
static const bool video_3ds_lcd_bottom = true;
/* Sets video display mode (3D, 2D, etc.) */
static const unsigned video_3ds_display_mode = CTR_VIDEO_MODE_3D;
#endif
#ifdef WIIU
/* On Wii U, whether to optimize for the native TV resolution
* or exactly 2x the Wii U GamePad resolution. */
#define DEFAULT_WIIU_PREFER_DRC false
#endif
/* AUDIO */
/* Will enable audio or not. */
@@ -1144,7 +1158,7 @@ static const bool audio_enable_menu_bgm = false;
#define DEFAULT_REWIND_GRANULARITY 1
#endif
/* Pause gameplay when gameplay loses focus. */
#if defined(EMSCRIPTEN) || defined(WEBOS)
#if defined(EMSCRIPTEN)
#define DEFAULT_PAUSE_NONACTIVE false
#else
#define DEFAULT_PAUSE_NONACTIVE true
@@ -1252,6 +1266,10 @@ static const bool savestate_thumbnail_enable = false;
/* Maximum fast forward ratio. */
#define DEFAULT_FASTFORWARD_RATIO 0.0
#define MAXIMUM_FASTFORWARD_RATIO 50.0
/* Skip frames when fast forwarding. */
#define DEFAULT_FASTFORWARD_FRAMESKIP true
/* Enable runloop for variable refresh rate screens. Force x1 speed while handling fast forward too. */
#define DEFAULT_VRR_RUNLOOP_ENABLE false
+21
View File
@@ -304,6 +304,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN,
RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
@@ -886,6 +893,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN,
RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
@@ -1468,6 +1482,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_SLOWMOTION_HOLD_KEY, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE, RETROK_UNKNOWN,
RARCH_VRR_RUNLOOP_TOGGLE, NO_BTN, NO_BTN, 0,
true
},
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
-6
View File
@@ -302,12 +302,6 @@
#define SUPPORTS_NETPLAY false
#endif
#ifdef HAVE_PYTHON
#define SUPPORTS_PYTHON true
#else
#define SUPPORTS_PYTHON false
#endif
#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)
#define SUPPORTS_COCOA true
#else
+237 -194
View File
@@ -308,6 +308,7 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
DECLARE_META_BIND(2, hold_fast_forward, RARCH_FAST_FORWARD_HOLD_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY),
DECLARE_META_BIND(1, toggle_slowmotion, RARCH_SLOWMOTION_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY),
DECLARE_META_BIND(2, hold_slowmotion, RARCH_SLOWMOTION_HOLD_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY),
DECLARE_META_BIND(2, toggle_vrr_runloop, RARCH_VRR_RUNLOOP_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE),
DECLARE_META_BIND(1, load_state, RARCH_LOAD_STATE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY),
DECLARE_META_BIND(1, save_state, RARCH_SAVE_STATE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY),
DECLARE_META_BIND(2, toggle_fullscreen, RARCH_FULLSCREEN_TOGGLE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY),
@@ -1654,6 +1655,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("ui_menubar_enable", &settings->bools.ui_menubar_enable, true, DEFAULT_UI_MENUBAR_ENABLE, false);
SETTING_BOOL("suspend_screensaver_enable", &settings->bools.ui_suspend_screensaver_enable, true, true, false);
SETTING_BOOL("rewind_enable", &settings->bools.rewind_enable, true, DEFAULT_REWIND_ENABLE, false);
SETTING_BOOL("fastforward_frameskip", &settings->bools.fastforward_frameskip, true, DEFAULT_FASTFORWARD_FRAMESKIP, false);
SETTING_BOOL("vrr_runloop_enable", &settings->bools.vrr_runloop_enable, true, DEFAULT_VRR_RUNLOOP_ENABLE, false);
SETTING_BOOL("apply_cheats_after_toggle", &settings->bools.apply_cheats_after_toggle, true, DEFAULT_APPLY_CHEATS_AFTER_TOGGLE, false);
SETTING_BOOL("apply_cheats_after_load", &settings->bools.apply_cheats_after_load, true, DEFAULT_APPLY_CHEATS_AFTER_LOAD, false);
@@ -1861,6 +1863,9 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("menu_show_online_updater", &settings->bools.menu_show_online_updater, true, menu_show_online_updater, false);
SETTING_BOOL("menu_show_core_updater", &settings->bools.menu_show_core_updater, true, menu_show_core_updater, false);
SETTING_BOOL("menu_show_legacy_thumbnail_updater", &settings->bools.menu_show_legacy_thumbnail_updater, true, menu_show_legacy_thumbnail_updater, false);
#ifdef HAVE_MIST
SETTING_BOOL("menu_show_core_manager_steam", &settings->bools.menu_show_core_manager_steam, true, menu_show_core_manager_steam, false);
#endif
SETTING_BOOL("filter_by_current_core", &settings->bools.filter_by_current_core, true, DEFAULT_FILTER_BY_CURRENT_CORE, false);
SETTING_BOOL("rgui_show_start_screen", &settings->bools.menu_show_start_screen, false, false /* TODO */, false);
SETTING_BOOL("menu_navigation_wraparound_enable", &settings->bools.menu_navigation_wraparound_enable, true, true, false);
@@ -1898,7 +1903,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("cheevos_test_unofficial", &settings->bools.cheevos_test_unofficial, true, false, false);
SETTING_BOOL("cheevos_hardcore_mode_enable", &settings->bools.cheevos_hardcore_mode_enable, true, true, false);
SETTING_BOOL("cheevos_challenge_indicators", &settings->bools.cheevos_challenge_indicators, true, true, false);
SETTING_BOOL("cheevos_richpresence_enable", &settings->bools.cheevos_richpresence_enable, true, false, false);
SETTING_BOOL("cheevos_richpresence_enable", &settings->bools.cheevos_richpresence_enable, true, true, false);
SETTING_BOOL("cheevos_unlock_sound_enable", &settings->bools.cheevos_unlock_sound_enable, true, false, false);
SETTING_BOOL("cheevos_verbose_enable", &settings->bools.cheevos_verbose_enable, true, true, false);
SETTING_BOOL("cheevos_auto_screenshot", &settings->bools.cheevos_auto_screenshot, true, false, false);
@@ -1976,9 +1981,14 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("sustained_performance_mode", &settings->bools.sustained_performance_mode, true, sustained_performance_mode, false);
#ifdef _3DS
SETTING_BOOL("new3ds_speedup_enable", &settings->bools.new3ds_speedup_enable, true, new3ds_speedup_enable, false);
SETTING_BOOL("video_3ds_lcd_bottom", &settings->bools.video_3ds_lcd_bottom, true, video_3ds_lcd_bottom, false);
#endif
#ifdef WIIU
SETTING_BOOL("video_wiiu_prefer_drc", &settings->bools.video_wiiu_prefer_drc, true, DEFAULT_WIIU_PREFER_DRC, false);
#endif
SETTING_BOOL("playlist_use_old_format", &settings->bools.playlist_use_old_format, true, DEFAULT_PLAYLIST_USE_OLD_FORMAT, false);
SETTING_BOOL("playlist_compression", &settings->bools.playlist_compression, true, DEFAULT_PLAYLIST_COMPRESSION, false);
SETTING_BOOL("content_runtime_log", &settings->bools.content_runtime_log, true, DEFAULT_CONTENT_RUNTIME_LOG, false);
@@ -2061,6 +2071,9 @@ static struct config_float_setting *populate_settings_float(
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
SETTING_FLOAT("menu_screensaver_animation_speed", &settings->floats.menu_screensaver_animation_speed, true, DEFAULT_MENU_SCREENSAVER_ANIMATION_SPEED, false);
#endif
#ifdef HAVE_OZONE
SETTING_FLOAT("ozone_thumbnail_scale_factor", &settings->floats.ozone_thumbnail_scale_factor, true, DEFAULT_OZONE_THUMBNAIL_SCALE_FACTOR, false);
#endif
#endif
SETTING_FLOAT("video_message_pos_x", &settings->floats.video_msg_pos_x, true, message_pos_offset_x, false);
SETTING_FLOAT("video_message_pos_y", &settings->floats.video_msg_pos_y, true, message_pos_offset_y, false);
@@ -2161,6 +2174,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("menu_ticker_type", &settings->uints.menu_ticker_type, true, DEFAULT_MENU_TICKER_TYPE, false);
SETTING_UINT("menu_scroll_delay", &settings->uints.menu_scroll_delay, true, DEFAULT_MENU_SCROLL_DELAY, false);
SETTING_UINT("content_show_add_entry", &settings->uints.menu_content_show_add_entry, true, DEFAULT_MENU_CONTENT_SHOW_ADD_ENTRY, false);
SETTING_UINT("content_show_contentless_cores", &settings->uints.menu_content_show_contentless_cores, true, DEFAULT_MENU_CONTENT_SHOW_CONTENTLESS_CORES, false);
SETTING_UINT("menu_screensaver_timeout", &settings->uints.menu_screensaver_timeout, true, DEFAULT_MENU_SCREENSAVER_TIMEOUT, false);
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
SETTING_UINT("menu_screensaver_animation", &settings->uints.menu_screensaver_animation, true, DEFAULT_MENU_SCREENSAVER_ANIMATION, false);
@@ -2197,6 +2211,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("menu_font_color_blue", &settings->uints.menu_font_color_blue, true, menu_font_color_blue, false);
SETTING_UINT("menu_xmb_thumbnail_scale_factor", &settings->uints.menu_xmb_thumbnail_scale_factor, true, xmb_thumbnail_scale_factor, false);
SETTING_UINT("menu_xmb_vertical_fade_factor",&settings->uints.menu_xmb_vertical_fade_factor, true, DEFAULT_XMB_VERTICAL_FADE_FACTOR, false);
SETTING_UINT("menu_xmb_title_margin", &settings->uints.menu_xmb_title_margin, true, DEFAULT_XMB_TITLE_MARGIN, false);
#endif
SETTING_UINT("materialui_menu_color_theme", &settings->uints.menu_materialui_color_theme, true, DEFAULT_MATERIALUI_THEME, false);
SETTING_UINT("materialui_menu_transition_animation", &settings->uints.menu_materialui_transition_animation, true, DEFAULT_MATERIALUI_TRANSITION_ANIM, false);
@@ -2620,7 +2635,7 @@ void config_set_defaults(void *data)
#endif
input_config_reset();
input_remapping_deinit();
input_remapping_deinit(false);
input_remapping_set_defaults(false);
/* Verify that binds are in proper order. */
@@ -3408,9 +3423,6 @@ static bool config_load_file(global_t *global,
snprintf(buf, sizeof(buf), "input_player%u_mouse_index", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_mouse_index[i], buf);
snprintf(buf, sizeof(buf), "input_libretro_device_p%u", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], buf);
}
/* LED map for use by the led driver */
@@ -3821,34 +3833,45 @@ bool config_load_override(void *data)
const char *core_name = system ?
system->info.library_name : NULL;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
const char *game_name = path_basename(rarch_path_basename);
const char *game_name = NULL;
settings_t *settings = config_st;
bool has_content = !string_is_empty(rarch_path_basename);
if (!string_is_empty(rarch_path_basename))
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
core_path[0] = '\0';
game_path[0] = '\0';
content_path[0] = '\0';
content_dir_name[0] = '\0';
config_directory[0] = '\0';
if (string_is_empty(core_name) || string_is_empty(game_name))
/* Cannot load an override if we have no core */
if (string_is_empty(core_name))
return false;
config_directory[0] = core_path[0] = game_path[0] = '\0';
fill_pathname_application_special(config_directory, sizeof(config_directory),
/* Get base config directory */
fill_pathname_application_special(config_directory,
sizeof(config_directory),
APPLICATION_SPECIAL_DIRECTORY_CONFIG);
/* Concatenate strings into full paths for core_path, game_path,
* content_path */
fill_pathname_join_special_ext(game_path,
config_directory, core_name,
game_name,
".cfg",
sizeof(game_path));
/* Concatenate strings into full paths for core_path,
* game_path, content_path */
if (has_content)
{
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
game_name = path_basename(rarch_path_basename);
fill_pathname_join_special_ext(content_path,
config_directory, core_name,
content_dir_name,
".cfg",
sizeof(content_path));
fill_pathname_join_special_ext(game_path,
config_directory, core_name,
game_name,
".cfg",
sizeof(game_path));
fill_pathname_join_special_ext(content_path,
config_directory, core_name,
content_dir_name,
".cfg",
sizeof(content_path));
}
fill_pathname_join_special_ext(core_path,
config_directory, core_name,
@@ -3871,69 +3894,72 @@ bool config_load_override(void *data)
RARCH_LOG("[Overrides]: No core-specific overrides found at \"%s\".\n",
core_path);
/* per-content-dir overrides */
/* Create a new config file from content_path */
if (config_file_exists(content_path))
if (has_content)
{
char temp_path[PATH_MAX_LENGTH];
/* per-content-dir overrides */
/* Create a new config file from content_path */
if (config_file_exists(content_path))
{
char temp_path[PATH_MAX_LENGTH];
RARCH_LOG("[Overrides]: Content dir-specific overrides found at \"%s\".\n",
RARCH_LOG("[Overrides]: Content dir-specific overrides found at \"%s\".\n",
content_path);
if (should_append)
{
RARCH_LOG("[Overrides]: Content dir-specific overrides stacking on top of previous overrides.\n");
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
content_path
);
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, content_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
should_append = true;
}
else
RARCH_LOG("[Overrides]: No content-dir-specific overrides found at \"%s\".\n",
content_path);
if (should_append)
/* per-game overrides */
/* Create a new config file from game_path */
if (config_file_exists(game_path))
{
RARCH_LOG("[Overrides]: Content dir-specific overrides stacking on top of previous overrides.\n");
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
content_path
);
char temp_path[PATH_MAX_LENGTH];
RARCH_LOG("[Overrides]: Game-specific overrides found at \"%s\".\n",
game_path);
if (should_append)
{
RARCH_LOG("[Overrides]: Game-specific overrides stacking on top of previous overrides.\n");
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
game_path
);
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, game_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
should_append = true;
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, content_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
should_append = true;
RARCH_LOG("[Overrides]: No game-specific overrides found at \"%s\".\n",
game_path);
}
else
RARCH_LOG("[Overrides]: No content-dir-specific overrides found at \"%s\".\n",
content_path);
/* per-game overrides */
/* Create a new config file from game_path */
if (config_file_exists(game_path))
{
char temp_path[PATH_MAX_LENGTH];
RARCH_LOG("[Overrides]: Game-specific overrides found at \"%s\".\n",
game_path);
if (should_append)
{
RARCH_LOG("[Overrides]: Game-specific overrides stacking on top of previous overrides.\n");
snprintf(temp_path, sizeof(temp_path),
"%s|%s",
path_get(RARCH_PATH_CONFIG_APPEND),
game_path
);
}
else
{
temp_path[0] = '\0';
strlcpy(temp_path, game_path, sizeof(temp_path));
}
path_set(RARCH_PATH_CONFIG_APPEND, temp_path);
should_append = true;
}
else
RARCH_LOG("[Overrides]: No game-specific overrides found at \"%s\".\n",
game_path);
if (!should_append)
return false;
@@ -4008,9 +4034,7 @@ bool config_unload_override(void)
bool config_load_remap(const char *directory_input_remapping,
void *data)
{
char content_dir_name[PATH_MAX_LENGTH] = { 0 };
/* path to the directory containing retroarch.cfg (prefix) */
char remap_directory[PATH_MAX_LENGTH];
char content_dir_name[PATH_MAX_LENGTH];
/* final path for core-specific configuration (prefix+suffix) */
char core_path[PATH_MAX_LENGTH];
/* final path for game-specific configuration (prefix+suffix) */
@@ -4021,52 +4045,56 @@ bool config_load_remap(const char *directory_input_remapping,
rarch_system_info_t *system = (rarch_system_info_t*)data;
const char *core_name = system ? system->info.library_name : NULL;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
const char *game_name = path_basename(rarch_path_basename);
const char *game_name = NULL;
bool has_content = !string_is_empty(rarch_path_basename);
enum msg_hash_enums msg_remap_loaded = MSG_GAME_REMAP_FILE_LOADED;
settings_t *settings = config_st;
bool notification_show_remap_load = settings->bools.notification_show_remap_load;
if (string_is_empty(core_name))
content_dir_name[0] = '\0';
core_path[0] = '\0';
game_path[0] = '\0';
content_path[0] = '\0';
/* > Cannot load remaps if we have no core
* > Cannot load remaps if remap directory is unset */
if (string_is_empty(core_name) ||
string_is_empty(directory_input_remapping))
return false;
/* Remap directory: remap_directory.
* Try remap directory setting, no fallbacks defined */
if (string_is_empty(directory_input_remapping))
return false;
RARCH_LOG("[Remaps]: Remap directory: \"%s\".\n", directory_input_remapping);
if (!string_is_empty(rarch_path_basename))
/* Concatenate strings into full paths for core_path,
* game_path, content_path */
if (has_content)
{
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
game_name = path_basename(rarch_path_basename);
remap_directory[0] = core_path[0] = game_path[0] = '\0';
fill_pathname_join_special_ext(game_path,
directory_input_remapping, core_name,
game_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(game_path));
strlcpy(remap_directory,
directory_input_remapping, sizeof(remap_directory));
RARCH_LOG("[Remaps]: Remap directory: \"%s\".\n", remap_directory);
fill_pathname_join_special_ext(content_path,
directory_input_remapping, core_name,
content_dir_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(content_path));
}
/* Concatenate strings into full paths for core_path, game_path */
fill_pathname_join_special_ext(core_path,
remap_directory, core_name,
directory_input_remapping, core_name,
core_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(core_path));
fill_pathname_join_special_ext(content_path,
remap_directory, core_name,
content_dir_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(content_path));
fill_pathname_join_special_ext(game_path,
remap_directory, core_name,
game_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(game_path));
input_remapping_set_defaults(false);
/* If a game remap file exists, load it. */
if ((new_conf = config_file_new_from_path_to_string(game_path)))
if (has_content && (new_conf = config_file_new_from_path_to_string(game_path)))
{
bool ret = input_remapping_load_file(new_conf, game_path);
config_file_free(new_conf);
@@ -4082,7 +4110,7 @@ bool config_load_remap(const char *directory_input_remapping,
}
/* If a content-dir remap file exists, load it. */
if ((new_conf = config_file_new_from_path_to_string(content_path)))
if (has_content && (new_conf = config_file_new_from_path_to_string(content_path)))
{
bool ret = input_remapping_load_file(new_conf, content_path);
config_file_free(new_conf);
@@ -4674,8 +4702,6 @@ bool config_save_file(const char *path)
config_set_int(conf, cfg, settings->uints.input_device[i]);
snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
config_set_int(conf, cfg, settings->uints.input_joypad_index[i]);
snprintf(cfg, sizeof(cfg), "input_libretro_device_p%u", i + 1);
config_set_int(conf, cfg, input_config_get_device(i));
snprintf(cfg, sizeof(cfg), "input_player%u_analog_dpad_mode", i + 1);
config_set_int(conf, cfg, settings->uints.input_analog_dpad_mode[i]);
snprintf(cfg, sizeof(cfg), "input_player%u_mouse_index", i + 1);
@@ -4787,6 +4813,7 @@ bool config_save_overrides(enum override_type type, void *data)
char core_path[PATH_MAX_LENGTH];
char game_path[PATH_MAX_LENGTH];
char content_path[PATH_MAX_LENGTH];
char content_dir_name[PATH_MAX_LENGTH];
settings_t *overrides = config_st;
int bool_settings_size = sizeof(settings->bools) / sizeof(settings->bools.placeholder);
int float_settings_size = sizeof(settings->floats) / sizeof(settings->floats.placeholder);
@@ -4798,50 +4825,38 @@ bool config_save_overrides(enum override_type type, void *data)
rarch_system_info_t *system = (rarch_system_info_t*)data;
const char *core_name = system ? system->info.library_name : NULL;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
const char *game_name = path_basename(rarch_path_basename);
char content_dir_name[PATH_MAX_LENGTH];
const char *game_name = NULL;
bool has_content = !string_is_empty(rarch_path_basename);
if (!string_is_empty(rarch_path_basename))
fill_pathname_parent_dir_name(content_dir_name, rarch_path_basename, sizeof(content_dir_name));
config_directory[0] = '\0';
override_directory[0] = '\0';
core_path[0] = '\0';
game_path[0] = '\0';
content_path[0] = '\0';
content_dir_name[0] = '\0';
if (string_is_empty(core_name) || string_is_empty(game_name))
/* > Cannot save an override if we have no core
* > Cannot save a per-game or per-content-directory
* override if we have no content */
if (string_is_empty(core_name) ||
(!has_content && (type != OVERRIDE_CORE)))
return false;
settings = (settings_t*)calloc(1, sizeof(settings_t));
settings = (settings_t*)calloc(1, sizeof(settings_t));
conf = config_file_new_alloc();
config_directory[0] = override_directory[0] = core_path[0] =
game_path[0] = '\0';
fill_pathname_application_special(config_directory, sizeof(config_directory),
/* Get base config directory */
fill_pathname_application_special(config_directory,
sizeof(config_directory),
APPLICATION_SPECIAL_DIRECTORY_CONFIG);
fill_pathname_join(override_directory, config_directory, core_name,
fill_pathname_join(override_directory,
config_directory, core_name,
sizeof(override_directory));
/* Ensure base config directory exists */
if (!path_is_directory(override_directory))
path_mkdir(override_directory);
/* Concatenate strings into full paths for core_path, game_path */
fill_pathname_join_special_ext(game_path,
config_directory, core_name,
game_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(game_path));
fill_pathname_join_special_ext(content_path,
config_directory, core_name,
content_dir_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(content_path));
fill_pathname_join_special_ext(core_path,
config_directory, core_name,
core_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(core_path));
if (!conf)
conf = config_file_new_alloc();
path_mkdir(override_directory);
/* Load the original config file in memory */
config_load_file(global_get_ptr(),
@@ -4967,14 +4982,32 @@ bool config_save_overrides(enum override_type type, void *data)
switch (type)
{
case OVERRIDE_CORE:
fill_pathname_join_special_ext(core_path,
config_directory, core_name,
core_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(core_path));
RARCH_LOG ("[Overrides]: Path \"%s\".\n", core_path);
ret = config_file_write(conf, core_path, true);
break;
case OVERRIDE_GAME:
game_name = path_basename(rarch_path_basename);
fill_pathname_join_special_ext(game_path,
config_directory, core_name,
game_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(game_path));
RARCH_LOG ("[Overrides]: Path \"%s\".\n", game_path);
ret = config_file_write(conf, game_path, true);
break;
case OVERRIDE_CONTENT_DIR:
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
fill_pathname_join_special_ext(content_path,
config_directory, core_name,
content_dir_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(content_path));
RARCH_LOG ("[Overrides]: Path \"%s\".\n", content_path);
ret = config_file_write(conf, content_path, true);
break;
@@ -5070,7 +5103,7 @@ bool input_remapping_load_file(void *data, const char *path)
if (!string_is_empty(runloop_st->name.remapfile))
{
input_remapping_deinit();
input_remapping_deinit(false);
input_remapping_set_defaults(false);
}
runloop_st->name.remapfile = strdup(path);
@@ -5131,13 +5164,7 @@ bool input_remapping_load_file(void *data, const char *path)
key_ident[0] = '\0';
fill_pathname_join_delim(stk_ident, s3,
key_string, '$', sizeof(stk_ident));
snprintf(stk_ident,
sizeof(stk_ident),
"%s_%s",
s3,
key_string);
key_string, '_', sizeof(stk_ident));
if (config_get_int(conf, stk_ident, &stk_remap))
{
@@ -5181,7 +5208,7 @@ bool input_remapping_load_file(void *data, const char *path)
/**
* input_remapping_save_file:
* @path : Path to remapping file (relative path).
* @path : Path to remapping file.
*
* Saves remapping values to file.
*
@@ -5191,23 +5218,33 @@ bool input_remapping_save_file(const char *path)
{
bool ret;
unsigned i, j;
char remap_file[PATH_MAX_LENGTH];
char remap_file_dir[PATH_MAX_LENGTH];
char key_strings[RARCH_FIRST_CUSTOM_BIND + 8][8] = {
"b", "y", "select", "start",
"up", "down", "left", "right",
"a", "x", "l", "r", "l2", "r2",
"l3", "r3", "l_x+", "l_x-", "l_y+", "l_y-", "r_x+", "r_x-", "r_y+", "r_y-" };
config_file_t *conf = NULL;
settings_t *settings = config_st;
unsigned max_users = settings->uints.input_max_users;
const char *dir_input_remapping = settings->paths.directory_input_remapping;
const char *remap_file = path;
config_file_t *conf = NULL;
runloop_state_t *runloop_st = runloop_state_get_ptr();
settings_t *settings = config_st;
unsigned max_users = settings->uints.input_max_users;
remap_file[0] = '\0';
remap_file_dir[0] = '\0';
fill_pathname_join_concat(remap_file, dir_input_remapping, path,
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file));
if (string_is_empty(remap_file))
return false;
/* Create output directory, if required */
strlcpy(remap_file_dir, remap_file, sizeof(remap_file_dir));
path_parent_dir(remap_file_dir);
if (!string_is_empty(remap_file_dir) &&
!path_is_directory(remap_file_dir) &&
!path_mkdir(remap_file_dir))
return false;
/* Attempt to load file */
if (!(conf = config_file_new_from_path_to_string(remap_file)))
{
if (!(conf = config_file_new_alloc()))
@@ -5253,14 +5290,20 @@ bool input_remapping_save_file(const char *path)
for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
{
char btn_ident[128];
char key_ident[128];
const char *key_string = key_strings[j];
unsigned remap_id = settings->uints.input_remap_ids[i][j];
unsigned keymap_id = settings->uints.input_keymapper_ids[i][j];
const char *key_string = key_strings[j];
btn_ident[0] = '\0';
key_ident[0] = '\0';
fill_pathname_join_delim(btn_ident, s1,
key_string, '_', sizeof(btn_ident));
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
/* only save values that have been modified */
/* Only save modified button values */
if (remap_id == j)
config_unset(conf, btn_ident);
else
@@ -5272,48 +5315,48 @@ bool input_remapping_save_file(const char *path)
settings->uints.input_remap_ids[i][j]);
}
if (keymap_id != RETROK_UNKNOWN)
{
char key_ident[128];
key_ident[0] = '\0';
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
/* Only save non-empty keymapper values */
if (keymap_id == RETROK_UNKNOWN)
config_unset(conf, key_ident);
else
config_set_int(conf, key_ident,
settings->uints.input_keymapper_ids[i][j]);
}
}
for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++)
{
char stk_ident[128];
char key_ident[128];
const char *key_string = key_strings[j];
unsigned remap_id = settings->uints.input_remap_ids[i][j];
unsigned keymap_id = settings->uints.input_keymapper_ids[i][j];
const char *key_string = key_strings[j];
stk_ident[0] = '\0';
key_ident[0] = '\0';
fill_pathname_join_delim(stk_ident, s3,
key_string, '_', sizeof(stk_ident));
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
/* Only save modified button values */
if (remap_id == j)
config_unset(conf, stk_ident);
else
{
if (remap_id == RARCH_UNMAPPED)
config_set_int(conf, stk_ident,
-1);
config_set_int(conf, stk_ident, -1);
else
config_set_int(conf, stk_ident,
settings->uints.input_remap_ids[i][j]);
}
if (keymap_id != RETROK_UNKNOWN)
{
char key_ident[128];
key_ident[0] = '\0';
fill_pathname_join_delim(key_ident, s2,
key_string, '_', sizeof(key_ident));
/* Only save non-empty keymapper values */
if (keymap_id == RETROK_UNKNOWN)
config_unset(conf, key_ident);
else
config_set_int(conf, key_ident,
settings->uints.input_keymapper_ids[i][j]);
}
}
snprintf(s1, sizeof(s1), "input_libretro_device_p%u", i + 1);
@@ -5329,18 +5372,18 @@ bool input_remapping_save_file(const char *path)
ret = config_file_write(conf, remap_file, true);
config_file_free(conf);
return ret;
}
/* Cache remap file path
* > Must guard against the case where
* runloop_st->name.remapfile itself
* is passed to this function... */
if (runloop_st->name.remapfile != remap_file)
{
if (runloop_st->name.remapfile)
free(runloop_st->name.remapfile);
runloop_st->name.remapfile = strdup(remap_file);
}
bool input_remapping_remove_file(const char *path,
const char *dir_input_remapping)
{
char remap_file[PATH_MAX_LENGTH];
remap_file[0] = '\0';
fill_pathname_join_concat(remap_file, dir_input_remapping, path,
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file));
return filestream_delete(remap_file) == 0 ? true : false;
return ret;
}
#endif
+12 -2
View File
@@ -156,8 +156,7 @@ typedef struct settings
unsigned input_joypad_index[MAX_USERS];
unsigned input_device[MAX_USERS];
unsigned input_mouse_index[MAX_USERS];
/* Set by autoconfiguration in joypad_autoconfig_dir.
* Does not override main binds. */
unsigned input_libretro_device[MAX_USERS];
unsigned input_analog_dpad_mode[MAX_USERS];
@@ -279,6 +278,7 @@ typedef struct settings
unsigned menu_xmb_color_theme;
unsigned menu_xmb_thumbnail_scale_factor;
unsigned menu_xmb_vertical_fade_factor;
unsigned menu_xmb_title_margin;
unsigned menu_materialui_color_theme;
unsigned menu_materialui_transition_animation;
unsigned menu_materialui_thumbnail_view_portrait;
@@ -295,6 +295,7 @@ typedef struct settings
unsigned menu_ticker_type;
unsigned menu_scroll_delay;
unsigned menu_content_show_add_entry;
unsigned menu_content_show_contentless_cores;
unsigned menu_screensaver_timeout;
unsigned menu_screensaver_animation;
@@ -368,6 +369,7 @@ typedef struct settings
float menu_ticker_speed;
float menu_rgui_particle_effect_speed;
float menu_screensaver_animation_speed;
float ozone_thumbnail_scale_factor;
float audio_max_timing_skew;
float audio_volume; /* dB scale. */
@@ -564,6 +566,7 @@ typedef struct settings
bool video_memory_show;
bool video_msg_bgcolor_enable;
bool video_3ds_lcd_bottom;
bool video_wiiu_prefer_drc;
bool video_notch_write_over_enable;
#ifdef HAVE_VIDEO_LAYOUT
bool video_layout_enable;
@@ -657,6 +660,9 @@ typedef struct settings
bool menu_horizontal_animation;
bool menu_scroll_fast;
bool menu_show_online_updater;
#ifdef HAVE_MIST
bool menu_show_core_manager_steam;
#endif
bool menu_show_core_updater;
bool menu_show_load_core;
bool menu_show_load_content;
@@ -834,6 +840,7 @@ typedef struct settings
bool history_list_enable;
bool playlist_entry_rename;
bool rewind_enable;
bool fastforward_frameskip;
bool vrr_runloop_enable;
bool apply_cheats_after_toggle;
bool apply_cheats_after_load;
@@ -918,6 +925,9 @@ typedef struct settings
bool ai_service_pause;
bool gamemode_enable;
#ifdef _3DS
bool new3ds_speedup_enable;
#endif
} bools;
} settings_t;
-4
View File
@@ -27,10 +27,6 @@
RETRO_BEGIN_DECLS
#ifdef HAVE_REWIND
bool core_set_rewind_callbacks(void);
#endif
#ifdef HAVE_NETWORKING
bool core_set_netplay_callbacks(void);
+423 -69
View File
@@ -48,6 +48,7 @@
/* Core Info Cache START */
/*************************/
#define CORE_INFO_CACHE_VERSION "1.2"
#define CORE_INFO_CACHE_DEFAULT_CAPACITY 8
/* TODO/FIXME: Apparently rzip compression is an issue on UWP */
@@ -60,6 +61,7 @@ typedef struct
core_info_t *items;
size_t length;
size_t capacity;
char *version;
bool refresh;
} core_info_cache_list_t;
@@ -103,7 +105,9 @@ static bool CCJSONObjectMemberHandler(void *context,
{
CCJSONContext *pCtx = (CCJSONContext *)context;
if ((pCtx->object_depth == 2) && (pCtx->array_depth == 1) && length)
if ((pCtx->object_depth == 2) &&
(pCtx->array_depth == 1) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_string_list_val = NULL;
@@ -199,26 +203,31 @@ static bool CCJSONObjectMemberHandler(void *context,
}
else if (string_is_equal(pValue, "supports_no_game"))
pCtx->current_entry_bool_val = &pCtx->core_info->supports_no_game;
else if (string_is_equal(pValue, "single_purpose"))
pCtx->current_entry_bool_val = &pCtx->core_info->single_purpose;
else if (string_is_equal(pValue, "savestate_support_level"))
pCtx->current_entry_uint_val = &pCtx->core_info->savestate_support_level;
break;
}
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 1) && length)
else if ((pCtx->object_depth == 3) &&
(pCtx->array_depth == 1) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_uint_val = NULL;
if (pCtx->to_core_file_id)
{
if (string_is_equal(pValue, "str"))
if (string_is_equal(pValue, "str"))
pCtx->current_string_val = &pCtx->core_info->core_file_id.str;
else if (string_is_equal(pValue, "hash"))
pCtx->current_entry_uint_val = &pCtx->core_info->core_file_id.hash;
}
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 2)
&& length)
else if ((pCtx->object_depth == 3) &&
(pCtx->array_depth == 2) &&
length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_bool_val = NULL;
@@ -227,7 +236,7 @@ static bool CCJSONObjectMemberHandler(void *context,
{
size_t firmware_idx = pCtx->core_info->firmware_count - 1;
if (string_is_equal(pValue, "path"))
if (string_is_equal(pValue, "path"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].path;
else if (string_is_equal(pValue, "desc"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].desc;
@@ -235,6 +244,15 @@ static bool CCJSONObjectMemberHandler(void *context,
pCtx->current_entry_bool_val = &pCtx->core_info->firmware[firmware_idx].optional;
}
}
else if ((pCtx->object_depth == 1) &&
(pCtx->array_depth == 0) &&
length)
{
pCtx->current_string_val = NULL;
if (string_is_equal(pValue, "version"))
pCtx->current_string_val = &pCtx->core_info_cache_list->version;
}
return true;
}
@@ -319,6 +337,11 @@ static bool CCJSONStartObjectHandler(void *context)
pCtx->core_info = (core_info_t*)calloc(1, sizeof(core_info_t));
if (!pCtx->core_info)
return false;
/* Assume all cores have 'full' savestate support
* by default */
pCtx->core_info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
else if ((pCtx->object_depth == 3) && (pCtx->array_depth == 2))
{
@@ -448,11 +471,14 @@ static void core_info_copy(core_info_t *src, core_info_t *dst)
? strdup(src->core_file_id.str) : NULL;
dst->core_file_id.hash = src->core_file_id.hash;
dst->savestate_support_level = src->savestate_support_level;
dst->has_info = src->has_info;
dst->supports_no_game = src->supports_no_game;
dst->single_purpose = src->single_purpose;
dst->database_match_archive_member = src->database_match_archive_member;
dst->is_experimental = src->is_experimental;
dst->is_locked = src->is_locked;
dst->is_standalone_exempt = src->is_standalone_exempt;
dst->is_installed = src->is_installed;
}
@@ -542,11 +568,14 @@ static void core_info_transfer(core_info_t *src, core_info_t *dst)
src->core_file_id.str = NULL;
dst->core_file_id.hash = src->core_file_id.hash;
dst->savestate_support_level = src->savestate_support_level;
dst->has_info = src->has_info;
dst->supports_no_game = src->supports_no_game;
dst->single_purpose = src->single_purpose;
dst->database_match_archive_member = src->database_match_archive_member;
dst->is_experimental = src->is_experimental;
dst->is_locked = src->is_locked;
dst->is_standalone_exempt = src->is_standalone_exempt;
dst->is_installed = src->is_installed;
}
@@ -565,6 +594,10 @@ static void core_info_cache_list_free(
}
free(core_info_cache_list->items);
if (core_info_cache_list->version)
free(core_info_cache_list->version);
free(core_info_cache_list);
}
@@ -657,6 +690,7 @@ static core_info_cache_list_t *core_info_cache_list_new(void)
core_info_cache_list->capacity = CORE_INFO_CACHE_DEFAULT_CAPACITY;
core_info_cache_list->refresh = false;
core_info_cache_list->version = NULL;
return core_info_cache_list;
}
@@ -758,6 +792,24 @@ static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
free(context.core_info);
}
if (!core_info_cache_list)
goto end;
/* If info cache file has the wrong version
* number, discard it */
if (string_is_empty(core_info_cache_list->version) ||
!string_is_equal(core_info_cache_list->version,
CORE_INFO_CACHE_VERSION))
{
RARCH_WARN("[Core Info] Core info cache has invalid version"
" - forcing refresh (required v%s, found v%s)\n",
CORE_INFO_CACHE_VERSION,
core_info_cache_list->version);
core_info_cache_list_free(context.core_info_cache_list);
core_info_cache_list = core_info_cache_list_new();
}
end:
intfstream_close(file);
free(file);
@@ -822,7 +874,7 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_add_string(writer, "version");
rjsonwriter_add_colon(writer);
rjsonwriter_add_space(writer);
rjsonwriter_add_string(writer, "1.0");
rjsonwriter_add_string(writer, CORE_INFO_CACHE_VERSION);
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 2);
@@ -1051,6 +1103,14 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "savestate_support_level");
rjsonwriter_add_colon(writer);
rjsonwriter_add_space(writer);
rjsonwriter_add_unsigned(writer, info->savestate_support_level);
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "has_info");
rjsonwriter_add_colon(writer);
@@ -1067,6 +1127,14 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "single_purpose");
rjsonwriter_add_colon(writer);
rjsonwriter_add_space(writer);
rjsonwriter_add_bool(writer, info->single_purpose);
rjsonwriter_add_comma(writer);
rjsonwriter_add_newline(writer);
rjsonwriter_add_spaces(writer, 6);
rjsonwriter_add_string(writer, "database_match_archive_member");
rjsonwriter_add_colon(writer);
@@ -1216,19 +1284,20 @@ typedef struct
{
const char *filename;
uint32_t hash;
} core_lock_file_path_t;
} core_aux_file_path_t;
typedef struct
{
core_lock_file_path_t *list;
core_aux_file_path_t *list;
size_t size;
} core_lock_file_path_list_t;
} core_aux_file_path_list_t;
typedef struct
{
struct string_list *dir_list;
core_file_path_list_t *core_list;
core_lock_file_path_list_t *lock_list;
core_aux_file_path_list_t *lock_list;
core_aux_file_path_list_t *standalone_exempt_list;
} core_path_list_t;
static uint32_t core_info_hash_string(const char *str)
@@ -1259,6 +1328,13 @@ static void core_info_path_list_free(core_path_list_t *path_list)
free(path_list->lock_list);
}
if (path_list->standalone_exempt_list)
{
if (path_list->standalone_exempt_list->list)
free(path_list->standalone_exempt_list->list);
free(path_list->standalone_exempt_list);
}
if (path_list->dir_list)
string_list_free(path_list->dir_list);
@@ -1286,22 +1362,30 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
goto error;
/* Allocate list containers */
path_list->dir_list = string_list_new();
path_list->core_list = (core_file_path_list_t*)calloc(1,
sizeof(*path_list->core_list));
path_list->lock_list = (core_lock_file_path_list_t*)calloc(1,
sizeof(*path_list->lock_list));
path_list->dir_list = string_list_new();
path_list->core_list = (core_file_path_list_t*)
calloc(1, sizeof(*path_list->core_list));
path_list->lock_list = (core_aux_file_path_list_t*)
calloc(1, sizeof(*path_list->lock_list));
path_list->standalone_exempt_list = (core_aux_file_path_list_t*)
calloc(1, sizeof(*path_list->standalone_exempt_list));
if ( !path_list->dir_list
|| !path_list->core_list
|| !path_list->lock_list)
|| !path_list->lock_list
|| !path_list->standalone_exempt_list)
goto error;
/* Get list of file extensions to include
* (core + lock file) */
fill_pathname_join_delim(exts,
core_exts, FILE_PATH_LOCK_EXTENSION_NO_DOT,
'|', sizeof(exts));
* > core + lock */
strlcpy(exts, core_exts, sizeof(exts));
strlcat(exts, "|" FILE_PATH_LOCK_EXTENSION_NO_DOT,
sizeof(exts));
#if defined(HAVE_DYNAMIC)
/* > 'standalone exempt' */
strlcat(exts, "|" FILE_PATH_STANDALONE_EXEMPT_EXTENSION_NO_DOT,
sizeof(exts));
#endif
/* Fetch core directory listing */
dir_list_ok = dir_list_append(path_list->dir_list,
@@ -1330,15 +1414,19 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
#endif
/* Allocate sub lists */
path_list->core_list->list = (core_file_path_t*)
path_list->core_list->list = (core_file_path_t*)
malloc(path_list->dir_list->size *
sizeof(*path_list->core_list->list));
path_list->lock_list->list = (core_lock_file_path_t*)
path_list->lock_list->list = (core_aux_file_path_t*)
malloc(path_list->dir_list->size *
sizeof(*path_list->lock_list->list));
path_list->standalone_exempt_list->list = (core_aux_file_path_t*)
malloc(path_list->dir_list->size *
sizeof(*path_list->standalone_exempt_list->list));
if (!path_list->core_list->list ||
!path_list->lock_list->list)
!path_list->lock_list->list ||
!path_list->standalone_exempt_list->list)
goto error;
/* Parse directory listing */
@@ -1353,7 +1441,8 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
|| !(file_ext = path_get_extension(filename)))
continue;
/* Check whether this is a core or lock file */
/* Check whether this is a core, lock or
* 'standalone exempt' file */
if (string_list_find_elem(core_ext_list, file_ext))
{
path_list->core_list->list[
@@ -1370,6 +1459,16 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
path_list->lock_list->size].hash = core_info_hash_string(filename);
path_list->lock_list->size++;
}
#if defined(HAVE_DYNAMIC)
else if (string_is_equal(file_ext, FILE_PATH_STANDALONE_EXEMPT_EXTENSION_NO_DOT))
{
path_list->standalone_exempt_list->list[
path_list->standalone_exempt_list->size].filename = filename;
path_list->standalone_exempt_list->list[
path_list->standalone_exempt_list->size].hash = core_info_hash_string(filename);
path_list->standalone_exempt_list->size++;
}
#endif
}
string_list_free(core_ext_list);
@@ -1382,13 +1481,15 @@ error:
}
static bool core_info_path_is_locked(
core_lock_file_path_list_t *lock_list,
core_aux_file_path_list_t *lock_list,
const char *core_file_name)
{
size_t i;
uint32_t hash;
char lock_filename[256];
lock_filename[0] = '\0';
if (lock_list->size < 1)
return false;
@@ -1399,7 +1500,7 @@ static bool core_info_path_is_locked(
for (i = 0; i < lock_list->size; i++)
{
core_lock_file_path_t *lock_file = &lock_list->list[i];
core_aux_file_path_t *lock_file = &lock_list->list[i];
if ((lock_file->hash == hash) &&
string_is_equal(lock_file->filename, lock_filename))
@@ -1409,6 +1510,37 @@ static bool core_info_path_is_locked(
return false;
}
static bool core_info_path_is_standalone_exempt(
core_aux_file_path_list_t *exempt_list,
const char *core_file_name)
{
size_t i;
uint32_t hash;
char exempt_filename[256];
exempt_filename[0] = '\0';
if (exempt_list->size < 1)
return false;
snprintf(exempt_filename, sizeof(exempt_filename),
"%s" FILE_PATH_STANDALONE_EXEMPT_EXTENSION,
core_file_name);
hash = core_info_hash_string(exempt_filename);
for (i = 0; i < exempt_list->size; i++)
{
core_aux_file_path_t *exempt_file = &exempt_list->list[i];
if ((exempt_file->hash == hash) &&
string_is_equal(exempt_file->filename, exempt_filename))
return true;
}
return false;
}
static bool core_info_get_file_id(const char *core_filename,
char *core_file_id, size_t len)
{
@@ -1695,6 +1827,10 @@ static void core_info_parse_config_file(
&tmp_bool))
info->supports_no_game = tmp_bool;
if (config_get_bool(conf, "single_purpose",
&tmp_bool))
info->single_purpose = tmp_bool;
if (config_get_bool(conf, "database_match_archive_member",
&tmp_bool))
info->database_match_archive_member = tmp_bool;
@@ -1703,6 +1839,40 @@ static void core_info_parse_config_file(
&tmp_bool))
info->is_experimental = tmp_bool;
/* Savestate support level is slightly more complex,
* since it is a value derived from two configuration
* parameters */
/* > Assume all cores have 'full' savestate support
* by default */
info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
/* > Check whether savestate functionality is defined
* in the info file */
if (config_get_bool(conf, "savestate", &tmp_bool))
{
if (tmp_bool)
{
/* Check if savestate features are defined */
entry = config_get_entry(conf, "savestate_features");
if (entry && !string_is_empty(entry->value))
{
if (string_is_equal(entry->value, "basic"))
info->savestate_support_level =
CORE_INFO_SAVESTATE_BASIC;
else if (string_is_equal(entry->value, "serialized"))
info->savestate_support_level =
CORE_INFO_SAVESTATE_SERIALIZED;
}
}
else
info->savestate_support_level =
CORE_INFO_SAVESTATE_DISABLED;
}
core_info_resolve_firmware(info, conf);
info->has_info = true;
@@ -1780,8 +1950,12 @@ static void core_info_free(core_info_t* info)
for (i = 0; i < info->firmware_count; i++)
{
free(info->firmware[i].path);
free(info->firmware[i].desc);
if (info->firmware[i].path)
free(info->firmware[i].path);
if (info->firmware[i].desc)
free(info->firmware[i].desc);
info->firmware[i].path = NULL;
info->firmware[i].desc = NULL;
}
free(info->firmware);
@@ -1879,23 +2053,35 @@ static core_info_list_t *core_info_list_new(const char *path,
if (info_cache)
{
core_info_copy(info_cache, info);
/* Core path is 'dynamic', and cannot
* be cached (i.e. core directory may
* change between runs) */
if (info->path)
free(info->path);
info->path = strdup(base_path);
info->path = strdup(base_path);
/* Core lock status is 'dynamic', and
* cannot be cached */
info->is_locked = core_info_path_is_locked(
path_list->lock_list, core_filename);
/* Core 'standalone exempt' status is 'dynamic',
* and cannot be cached
* > It is also dependent upon whether the core
* supports contentless operation */
info->is_standalone_exempt = info->supports_no_game &&
core_info_path_is_standalone_exempt(
path_list->standalone_exempt_list,
core_filename);
/* 'info_count' is normally incremented inside
* core_info_parse_config_file(). If core entry
* is cached, must instead increment the value
* here */
if (info->has_info)
core_info_list->info_count++;
continue;
}
}
@@ -1924,7 +2110,13 @@ static core_info_list_t *core_info_list_new(const char *path,
if (!info->display_name)
info->display_name = strdup(core_filename);
info->is_installed = true;
/* Get core 'standalone exempt' status */
info->is_standalone_exempt = info->supports_no_game &&
core_info_path_is_standalone_exempt(
path_list->standalone_exempt_list,
core_filename);
info->is_installed = true;
/* If info cache is enabled and we reach this
* point, current core is uncached
@@ -2093,10 +2285,14 @@ bool core_info_init_current_core(void)
return false;
current->has_info = false;
current->supports_no_game = false;
current->single_purpose = false;
current->database_match_archive_member = false;
current->is_experimental = false;
current->is_locked = false;
current->is_standalone_exempt = false;
current->is_installed = false;
current->firmware_count = 0;
current->savestate_support_level = CORE_INFO_SAVESTATE_DETERMINISTIC;
current->path = NULL;
current->display_name = NULL;
current->display_version = NULL;
@@ -2409,7 +2605,12 @@ bool core_info_list_get_display_name(
core_info_list_t *core_info_list,
const char *core_path, char *s, size_t len)
{
core_info_t *info = core_info_find_internal(
core_info_t *info;
if (!core_info_list)
return false;
info = core_info_find_internal(
core_info_list, core_path);
if (s &&
@@ -2916,6 +3117,99 @@ bool core_info_hw_api_supported(core_info_t *info)
#endif
}
bool core_info_current_supports_savestate(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_BASIC;
}
bool core_info_current_supports_rewind(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_SERIALIZED;
}
bool core_info_current_supports_netplay(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
bool core_info_current_supports_runahead(void)
{
core_info_state_t *p_coreinfo = &core_info_st;
/* If no core is currently loaded, assume
* by default that all savestate functionality
* is supported */
if (!p_coreinfo->current)
return true;
return p_coreinfo->current->savestate_support_level >=
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
static bool core_info_update_core_aux_file(const char *path, bool create)
{
bool aux_file_exists = false;
if (string_is_empty(path))
return false;
/* Check whether aux file exists */
aux_file_exists = path_is_valid(path);
/* Create or delete aux file, as required */
if (create && !aux_file_exists)
{
RFILE *aux_file = filestream_open(path,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!aux_file)
return false;
/* We have to write something - just output
* a single character */
if (filestream_putc(aux_file, 0) != 0)
{
filestream_close(aux_file);
return false;
}
filestream_close(aux_file);
}
else if (!create && aux_file_exists)
if (filestream_delete(path) != 0)
return false;
return true;
}
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached
@@ -2923,9 +3217,10 @@ bool core_info_hw_api_supported(core_info_t *info)
bool core_info_set_core_lock(const char *core_path, bool lock)
{
core_info_t *core_info = NULL;
bool lock_file_exists = false;
char lock_file_path[PATH_MAX_LENGTH];
lock_file_path[0] = '\0';
#if defined(ANDROID)
/* Play Store builds do not support
* core locking */
@@ -2933,47 +3228,19 @@ bool core_info_set_core_lock(const char *core_path, bool lock)
return false;
#endif
if (string_is_empty(core_path))
return false;
/* Search for specified core */
if (!core_info_find(core_path, &core_info))
return false;
if (string_is_empty(core_info->path))
if (string_is_empty(core_path) ||
!core_info_find(core_path, &core_info) ||
string_is_empty(core_info->path))
return false;
/* Get lock file path */
snprintf(lock_file_path, sizeof(lock_file_path),
"%s" FILE_PATH_LOCK_EXTENSION, core_info->path);
/* Check whether lock file exists */
lock_file_exists = path_is_valid(lock_file_path);
/* Create or delete lock file, as required */
if (lock && !lock_file_exists)
{
RFILE *lock_file = filestream_open(
lock_file_path,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!lock_file)
return false;
/* We have to write something - just output
* a single character */
if (filestream_putc(lock_file, 0) != 0)
{
filestream_close(lock_file);
return false;
}
filestream_close(lock_file);
}
else if (!lock && lock_file_exists)
if (filestream_delete(lock_file_path) != 0)
return false;
if (!core_info_update_core_aux_file(lock_file_path, lock))
return false;
/* File operations were successful - update
* core info entry */
@@ -2998,6 +3265,8 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
bool is_locked = false;
char lock_file_path[PATH_MAX_LENGTH];
lock_file_path[0] = '\0';
#if defined(ANDROID)
/* Play Store builds do not support
* core locking */
@@ -3038,3 +3307,88 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
return is_locked;
}
/* Sets 'standalone exempt' status of specified core
* > A 'standalone exempt' core will not be shown
* in the contentless cores menu when display type
* is set to 'custom'
* > Returns true if successful
* > Returns false if core does not support
* contentless operation
* > *Not* thread safe */
bool core_info_set_core_standalone_exempt(const char *core_path, bool exempt)
{
#if defined(HAVE_DYNAMIC)
core_info_t *core_info = NULL;
char exempt_file_path[PATH_MAX_LENGTH];
exempt_file_path[0] = '\0';
/* Search for specified core */
if (string_is_empty(core_path) ||
!core_info_find(core_path, &core_info) ||
string_is_empty(core_info->path) ||
!core_info->supports_no_game)
return false;
/* Get 'standalone exempt' file path */
snprintf(exempt_file_path, sizeof(exempt_file_path),
"%s" FILE_PATH_STANDALONE_EXEMPT_EXTENSION,
core_info->path);
/* Create or delete 'standalone exempt' file, as required */
if (!core_info_update_core_aux_file(exempt_file_path, exempt))
return false;
/* File operations were successful - update
* core info entry */
core_info->is_standalone_exempt = exempt;
return true;
#else
/* Static platforms do not support the contentless
* cores menu */
return false;
#endif
}
/* Fetches 'standalone exempt' status of specified core
* > Returns true if core should be excluded from
* the contentless cores menu when display type is
* set to 'custom'
* > *Not* thread safe */
bool core_info_get_core_standalone_exempt(const char *core_path)
{
#if defined(HAVE_DYNAMIC)
core_info_t *core_info = NULL;
bool is_exempt = false;
char exempt_file_path[PATH_MAX_LENGTH];
exempt_file_path[0] = '\0';
/* Search for specified core */
if (string_is_empty(core_path) ||
!core_info_find(core_path, &core_info) ||
string_is_empty(core_info->path) ||
!core_info->supports_no_game)
return false;
/* Get 'standalone exempt' file path */
snprintf(exempt_file_path, sizeof(exempt_file_path),
"%s" FILE_PATH_STANDALONE_EXEMPT_EXTENSION,
core_info->path);
/* Check whether 'standalone exempt' file exists */
is_exempt = path_is_valid(exempt_file_path);
/* Ensure that core info 'is_standalone_exempt'
* field is up to date */
core_info->is_standalone_exempt = is_exempt;
return is_exempt;
#else
/* Static platforms do not support the contentless
* cores menu */
return false;
#endif
}
+46
View File
@@ -25,6 +25,23 @@
RETRO_BEGIN_DECLS
/* Defines the levels of savestate support
* that may be offered by a core:
* - serialized: rewind
* - deterministic: netplay/runahead
* Thus:
* (level < CORE_INFO_SAVESTATE_BASIC)
* -> no savestate support
* (level < CORE_INFO_SAVESTATE_SERIALIZED)
* -> no rewind/netplay/runahead
* (level < CORE_INFO_SAVESTATE_DETERMINISTIC)
* -> no netplay/runahead
*/
#define CORE_INFO_SAVESTATE_DISABLED 0
#define CORE_INFO_SAVESTATE_BASIC 1
#define CORE_INFO_SAVESTATE_SERIALIZED 2
#define CORE_INFO_SAVESTATE_DETERMINISTIC 3
enum core_info_list_qsort_type
{
CORE_INFO_LIST_SORT_PATH = 0,
@@ -84,11 +101,14 @@ typedef struct
core_info_firmware_t *firmware;
core_file_id_t core_file_id; /* ptr alignment */
size_t firmware_count;
uint32_t savestate_support_level;
bool has_info;
bool supports_no_game;
bool single_purpose;
bool database_match_archive_member;
bool is_experimental;
bool is_locked;
bool is_standalone_exempt;
bool is_installed;
} core_info_t;
@@ -184,6 +204,16 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
bool core_info_hw_api_supported(core_info_t *info);
/* Convenience wrapper functions used to interpret
* the 'savestate_support_level' parameter of
* the currently loaded core. If no core is
* loaded, will return 'true' (since full
* savestate functionality is assumed by default) */
bool core_info_current_supports_savestate(void);
bool core_info_current_supports_rewind(void);
bool core_info_current_supports_netplay(void);
bool core_info_current_supports_runahead(void);
/* Sets 'locked' status of specified core
* > Returns true if successful
* > Like all functions that access the cached
@@ -200,6 +230,22 @@ bool core_info_set_core_lock(const char *core_path, bool lock);
* must be checked externally */
bool core_info_get_core_lock(const char *core_path, bool validate_path);
/* Sets 'standalone exempt' status of specified core
* > A 'standalone exempt' core will not be shown
* in the contentless cores menu when display type
* is set to 'custom'
* > Returns true if successful
* > Returns false if core does not support
* contentless operation
* > *Not* thread safe */
bool core_info_set_core_standalone_exempt(const char *core_path, bool exempt);
/* Fetches 'standalone exempt' status of specified core
* > Returns true if core should be excluded from
* the contentless cores menu when display type is
* set to 'custom'
* > *Not* thread safe */
bool core_info_get_core_standalone_exempt(const char *core_path);
bool core_info_core_file_id_is_equal(const char *core_path_a, const char *core_path_b);
/* When called, generates a temporary file
+1 -1
View File
@@ -737,7 +737,7 @@ static bool core_option_manager_parse_variable(
value, NULL);
/* Set value hash */
*value_hash = core_option_manager_hash_string(value);
*value_hash = core_option_manager_hash_string(value);
option->vals->elems[i].userdata = (void*)value_hash;
/* Redundant safely check... */
-56
View File
@@ -360,62 +360,6 @@ size_t libretro_videoprocessor_retro_get_memory_size(unsigned id);
#endif
#ifdef HAVE_GONG
/* Internal gong core. */
void libretro_gong_retro_init(void);
void libretro_gong_retro_deinit(void);
unsigned libretro_gong_retro_api_version(void);
void libretro_gong_retro_get_system_info(struct retro_system_info *info);
void libretro_gong_retro_get_system_av_info(struct retro_system_av_info *info);
void libretro_gong_retro_set_environment(retro_environment_t cb);
void libretro_gong_retro_set_video_refresh(retro_video_refresh_t cb);
void libretro_gong_retro_set_audio_sample(retro_audio_sample_t cb);
void libretro_gong_retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);
void libretro_gong_retro_set_input_poll(retro_input_poll_t cb);
void libretro_gong_retro_set_input_state(retro_input_state_t cb);
void libretro_gong_retro_set_controller_port_device(unsigned port, unsigned device);
void libretro_gong_retro_reset(void);
void libretro_gong_retro_run(void);
size_t libretro_gong_retro_serialize_size(void);
bool libretro_gong_retro_serialize(void *data, size_t size);
bool libretro_gong_retro_unserialize(const void *data, size_t size);
void libretro_gong_retro_cheat_reset(void);
void libretro_gong_retro_cheat_set(unsigned index, bool enabled, const char *code);
bool libretro_gong_retro_load_game(const struct retro_game_info *game);
bool libretro_gong_retro_load_game_special(unsigned game_type,
const struct retro_game_info *info, size_t num_info);
void libretro_gong_retro_unload_game(void);
unsigned libretro_gong_retro_get_region(void);
void *libretro_gong_retro_get_memory_data(unsigned id);
size_t libretro_gong_retro_get_memory_size(unsigned id);
#endif
RETRO_END_DECLS
#endif
+37 -31
View File
@@ -96,11 +96,8 @@ static unsigned sw_sws_threads;
static video_buffer_t *video_buffer;
static tpool_t *tpool;
/* If libavutil is at least version 55 or higher,
* and if libavcodec is at least version 57.80.100 or higher,
* enable hardware acceleration */
#define ENABLE_HW_ACCEL ((LIBAVUTIL_VERSION_MAJOR > 55) && ENABLE_HW_ACCEL_CHECK2())
#define ENABLE_HW_ACCEL_CHECK2() ((LIBAVCODEC_VERSION_MAJOR == 57 && LIBAVCODEC_VERSION_MINOR >= 80 && LIBAVCODEC_VERSION_MICRO >= 100) || (LIBAVCODEC_VERSION_MAJOR > 57))
#define FFMPEG3 ((LIBAVUTIL_VERSION_INT < (56, 6, 100)) || \
(LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)))
#if ENABLE_HW_ACCEL
static enum AVHWDeviceType hw_decoder;
@@ -240,7 +237,9 @@ void CORE_PREFIX(retro_init)(void)
{
reset_triggered = false;
#if FFMPEG3
av_register_all();
#endif
if (CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
libretro_supports_bitmasks = true;
@@ -462,10 +461,12 @@ static void check_variables(bool firststart)
hw_decoder = AV_HWDEVICE_TYPE_DRM;
else if (string_is_equal(hw_var.value, "dxva2"))
hw_decoder = AV_HWDEVICE_TYPE_DXVA2;
#if !FFMPEG3
else if (string_is_equal(hw_var.value, "mediacodec"))
hw_decoder = AV_HWDEVICE_TYPE_MEDIACODEC;
else if (string_is_equal(hw_var.value, "opencl"))
hw_decoder = AV_HWDEVICE_TYPE_OPENCL;
#endif
else if (string_is_equal(hw_var.value, "qsv"))
hw_decoder = AV_HWDEVICE_TYPE_QSV;
else if (string_is_equal(hw_var.value, "vaapi"))
@@ -988,8 +989,9 @@ static enum AVPixelFormat init_hw_decoder(struct AVCodecContext *ctx,
{
int ret = 0;
enum AVPixelFormat decoder_pix_fmt = AV_PIX_FMT_NONE;
struct AVCodec *codec = avcodec_find_decoder(fctx->streams[video_stream_index]->codec->codec_id);
const AVCodec *codec = avcodec_find_decoder(fctx->streams[video_stream_index]->codecpar->codec_id);
#if !FFMPEG3
for (int i = 0;; i++)
{
const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i);
@@ -1002,12 +1004,15 @@ static enum AVPixelFormat init_hw_decoder(struct AVCodecContext *ctx,
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
config->device_type == type)
{
enum AVPixelFormat device_pix_fmt = config->pix_fmt;
#else
enum AVPixelFormat device_pix_fmt =
pix_fmts ? ctx->get_format(ctx, pix_fmts) : decoder_pix_fmt;
#endif
log_cb(RETRO_LOG_INFO, "[FFMPEG] Selected HW decoder %s.\n",
av_hwdevice_get_type_name(type));
log_cb(RETRO_LOG_INFO, "[FFMPEG] Selected HW pixel format %s.\n",
av_get_pix_fmt_name(config->pix_fmt));
enum AVPixelFormat device_pix_fmt = config->pix_fmt;
av_get_pix_fmt_name(device_pix_fmt));
if (pix_fmts != NULL)
{
@@ -1019,16 +1024,17 @@ static enum AVPixelFormat init_hw_decoder(struct AVCodecContext *ctx,
goto exit;
}
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Codec %s does not support device pixel format %s.\n",
codec->name, av_get_pix_fmt_name(config->pix_fmt));
codec->name, av_get_pix_fmt_name(device_pix_fmt));
}
else
{
decoder_pix_fmt = device_pix_fmt;
goto exit;
}
#if !FFMPEG3
}
}
#endif
exit:
if (decoder_pix_fmt != AV_PIX_FMT_NONE)
@@ -1070,7 +1076,6 @@ static enum AVPixelFormat auto_hw_decoder(AVCodecContext *ctx,
}
#endif
static enum AVPixelFormat select_decoder(AVCodecContext *ctx,
const enum AVPixelFormat *pix_fmts)
{
@@ -1098,7 +1103,7 @@ static enum AVPixelFormat select_decoder(AVCodecContext *ctx,
ctx->thread_count = sw_decoder_threads;
log_cb(RETRO_LOG_INFO, "[FFMPEG] Configured software decoding threads: %d\n", sw_decoder_threads);
format = fctx->streams[video_stream_index]->codec->pix_fmt;
format = fctx->streams[video_stream_index]->codecpar->format;
#if ENABLE_HW_ACCEL
hw_decoding_enabled = false;
@@ -1132,14 +1137,15 @@ static bool open_codec(AVCodecContext **ctx, enum AVMediaType type, unsigned ind
{
int ret = 0;
AVCodec *codec = avcodec_find_decoder(fctx->streams[index]->codec->codec_id);
const AVCodec *codec = avcodec_find_decoder(fctx->streams[index]->codecpar->codec_id);
if (!codec)
{
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Couldn't find suitable decoder\n");
return false;
}
*ctx = fctx->streams[index]->codec;
*ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context((*ctx), fctx->streams[index]->codecpar);
if (type == AVMEDIA_TYPE_VIDEO)
{
@@ -1230,7 +1236,7 @@ static bool open_codecs(void)
for (i = 0; i < fctx->nb_streams; i++)
{
enum AVMediaType type = fctx->streams[i]->codec->codec_type;
enum AVMediaType type = fctx->streams[i]->codecpar->codec_type;
switch (type)
{
case AVMEDIA_TYPE_AUDIO:
@@ -1245,7 +1251,7 @@ static bool open_codecs(void)
case AVMEDIA_TYPE_VIDEO:
if (!vctx
&& !codec_is_image(fctx->streams[i]->codec->codec_id))
&& !codec_is_image(fctx->streams[i]->codecpar->codec_id))
{
if (!open_codec(&vctx, type, i))
return false;
@@ -1255,7 +1261,7 @@ static bool open_codecs(void)
case AVMEDIA_TYPE_SUBTITLE:
#ifdef HAVE_SSA
if (subtitle_streams_num < MAX_STREAMS
&& codec_id_is_ass(fctx->streams[i]->codec->codec_id))
&& codec_id_is_ass(fctx->streams[i]->codecpar->codec_id))
{
int size;
AVCodecContext **s = &sctx[subtitle_streams_num];
@@ -1280,9 +1286,9 @@ static bool open_codecs(void)
case AVMEDIA_TYPE_ATTACHMENT:
{
AVCodecContext *ctx = fctx->streams[i]->codec;
if (codec_id_is_ttf(ctx->codec_id))
append_attachment(ctx->extradata, ctx->extradata_size);
AVCodecParameters *params = fctx->streams[i]->codecpar;
if (codec_id_is_ttf(params->codec_id))
append_attachment(params->extradata, params->extradata_size);
}
break;
@@ -1464,12 +1470,12 @@ static void sws_worker_thread(void *arg)
ctx->sws = sws_getCachedContext(ctx->sws,
media.width, media.height, (enum AVPixelFormat)tmp_frame->format,
media.width, media.height, PIX_FMT_RGB32,
media.width, media.height, AV_PIX_FMT_RGB32,
SWS_POINT, NULL, NULL, NULL);
set_colorspace(ctx->sws, media.width, media.height,
av_frame_get_colorspace(tmp_frame),
av_frame_get_color_range(tmp_frame));
tmp_frame->colorspace,
tmp_frame->color_range);
if ((ret = sws_scale(ctx->sws, (const uint8_t *const*)tmp_frame->data,
tmp_frame->linesize, 0, media.height,
@@ -1620,7 +1626,7 @@ static int16_t *decode_audio(AVCodecContext *ctx, AVPacket *pkt,
#endif
break;
}
required_buffer = frame->nb_samples * sizeof(int16_t) * 2;
if (required_buffer > *buffer_cap)
{
@@ -1637,7 +1643,7 @@ static int16_t *decode_audio(AVCodecContext *ctx, AVPacket *pkt,
pts = frame->best_effort_timestamp;
slock_lock(fifo_lock);
while (!decode_thread_dead &&
while (!decode_thread_dead &&
FIFO_WRITE_AVAIL(audio_decode_fifo) < required_buffer)
{
if (!main_sleeping)
@@ -1740,7 +1746,7 @@ static void decode_thread(void *data)
if (video_stream_index >= 0)
{
frame_size = avpicture_get_size(PIX_FMT_RGB32, media.width, media.height);
frame_size = av_image_get_buffer_size(AV_PIX_FMT_RGB32, media.width, media.height, 1);
video_buffer = video_buffer_create(4, frame_size, media.width, media.height);
tpool = tpool_create(sw_sws_threads);
log_cb(RETRO_LOG_INFO, "[FFMPEG] Configured worker threads: %d\n", sw_sws_threads);
@@ -1813,7 +1819,7 @@ static void decode_thread(void *data)
if (!packet_buffer_empty(video_packet_buffer))
next_video_end = video_timebase * packet_buffer_peek_end_pts(video_packet_buffer);
/*
/*
* Decode audio packet if:
* 1. it's the start of file or it's audio only media
* 2. there is a video packet for in the buffer
@@ -1835,7 +1841,7 @@ static void decode_thread(void *data)
av_packet_unref(pkt);
}
/*
/*
* Decode video packet if:
* 1. we already decoded an audio packet
* 2. there is no audio stream to play
@@ -1865,7 +1871,7 @@ static void decode_thread(void *data)
av_packet_free(&pkt);
break;
}
// Read the next frame and stage it in case of audio or video frame.
if (av_read_frame(fctx, pkt) < 0)
eof = true;
@@ -1878,7 +1884,7 @@ static void decode_thread(void *data)
/**
* Decode subtitle packets right away, since SSA/ASS can operate this way.
* If we ever support other subtitles, we need to handle this with a
* buffer too
* buffer too
**/
AVSubtitle sub;
int finished = 0;
+8 -6
View File
@@ -2,6 +2,7 @@
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#ifdef __cplusplus
}
#endif
@@ -69,17 +70,18 @@ video_buffer_t *video_buffer_create(
b->buffer[i].pts = 0;
b->buffer[i].sws = sws_alloc_context();
b->buffer[i].source = av_frame_alloc();
#if LIBAVUTIL_VERSION_MAJOR > 55
#if ENABLE_HW_ACCEL
b->buffer[i].hw_source = av_frame_alloc();
#endif
b->buffer[i].target = av_frame_alloc();
avpicture_alloc((AVPicture*)b->buffer[i].target,
PIX_FMT_RGB32, width, height);
AVFrame* frame = b->buffer[i].target;
av_image_alloc(frame->data, frame->linesize,
width, height, AV_PIX_FMT_RGB32, 1);
if (!b->buffer[i].sws ||
!b->buffer[i].source ||
#if LIBAVUTIL_VERSION_MAJOR > 55
#if ENABLE_HW_ACCEL
!b->buffer[i].hw_source ||
#endif
!b->buffer[i].target)
@@ -106,11 +108,11 @@ void video_buffer_destroy(video_buffer_t *video_buffer)
{
for (i = 0; i < video_buffer->capacity; i++)
{
#if LIBAVUTIL_VERSION_MAJOR > 55
#if ENABLE_HW_ACCEL
av_frame_free(&video_buffer->buffer[i].hw_source);
#endif
av_frame_free(&video_buffer->buffer[i].source);
avpicture_free((AVPicture*)video_buffer->buffer[i].target);
av_freep((AVFrame*)video_buffer->buffer[i].target);
av_frame_free(&video_buffer->buffer[i].target);
sws_freeContext(video_buffer->buffer[i].sws);
}
+32 -30
View File
@@ -31,22 +31,24 @@ extern "C" {
RETRO_BEGIN_DECLS
#ifndef PIX_FMT_RGB32
#define PIX_FMT_RGB32 AV_PIX_FMT_RGB32
#endif
/* If libavutil is at least version 55,
* and if libavcodec is at least version 57.80.100,
* enable hardware acceleration */
#define ENABLE_HW_ACCEL ((LIBAVUTIL_VERSION_MAJOR >= 55) && \
(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100)))
/**
* video_decoder_context
*
*
* Context object for the sws worker threads.
*
*
*/
struct video_decoder_context
{
int64_t pts;
struct SwsContext *sws;
AVFrame *source;
#if LIBAVUTIL_VERSION_MAJOR > 55
#if ENABLE_HW_ACCEL
AVFrame *hw_source;
#endif
AVFrame *target;
@@ -60,15 +62,15 @@ typedef struct video_decoder_context video_decoder_context_t;
/**
* video_buffer
*
* The video buffer is a ring buffer, that can be used as a
*
* The video buffer is a ring buffer, that can be used as a
* buffer for many workers while keeping the order.
*
*
* It is thread safe in a sensem that it is designed to work
* with one work coordinator, that allocates work slots for
* workers threads to work on and later collect the work
* product in the same order, as the slots were allocated.
*
*
*/
struct video_buffer;
typedef struct video_buffer video_buffer_t;
@@ -81,38 +83,38 @@ typedef struct video_buffer video_buffer_t;
* @height : Height of the target frame.
*
* Create a video buffer.
*
*
* Returns: A video buffer.
*/
video_buffer_t *video_buffer_create(size_t capacity, int frame_size, int width, int height);
/**
/**
* video_buffer_destroy:
* @video_buffer : video buffer.
*
*
* Destroys a video buffer.
*
*
* Does also free the buffer allocated with video_buffer_create().
* User has to shut down any external worker threads that may have
* a reference to this video buffer.
*
*
**/
void video_buffer_destroy(video_buffer_t *video_buffer);
/**
/**
* video_buffer_clear:
* @video_buffer : video buffer.
*
*
* Clears a video buffer.
*
*
**/
void video_buffer_clear(video_buffer_t *video_buffer);
/**
/**
* video_buffer_get_open_slot:
* @video_buffer : video buffer.
* @context : sws context.
*
*
* Returns the next open context inside the ring buffer
* and it's index. The status of the slot will be marked as
* 'in progress' until slot is marked as finished with
@@ -121,21 +123,21 @@ void video_buffer_clear(video_buffer_t *video_buffer);
**/
void video_buffer_get_open_slot(video_buffer_t *video_buffer, video_decoder_context_t **context);
/**
/**
* video_buffer_return_open_slot:
* @video_buffer : video buffer.
* @context : sws context.
*
*
* Marks the given sws context that is "in progress" as "open" again.
*
**/
void video_buffer_return_open_slot(video_buffer_t *video_buffer, video_decoder_context_t *context);
/**
/**
* video_buffer_open_slot:
* @video_buffer : video buffer.
* @context : sws context.
*
*
* Sets the status of the given context from "finished" to "open".
* The slot is then available for producers to claim again with video_buffer_get_open_slot().
**/
@@ -145,7 +147,7 @@ void video_buffer_open_slot(video_buffer_t *video_buffer, video_decoder_context_
* video_buffer_get_finished_slot:
* @video_buffer : video buffer.
* @context : sws context.
*
*
* Returns a reference for the next context inside
* the ring buffer. User needs to use video_buffer_open_slot()
* to open the slot in the ringbuffer for the next
@@ -158,7 +160,7 @@ void video_buffer_get_finished_slot(video_buffer_t *video_buffer, video_decoder_
* video_buffer_finish_slot:
* @video_buffer : video buffer.
* @context : sws context.
*
*
* Sets the status of the given context from "in progress" to "finished".
* This is normally done by a producer. User can then retrieve the finished work
* context by calling video_buffer_get_finished_slot().
@@ -168,9 +170,9 @@ void video_buffer_finish_slot(video_buffer_t *video_buffer, video_decoder_contex
/**
* video_buffer_wait_for_open_slot:
* @video_buffer : video buffer.
*
*
* Blocks until open slot is available.
*
*
* Returns true if the buffer has a open slot available.
*/
bool video_buffer_wait_for_open_slot(video_buffer_t *video_buffer);
@@ -180,7 +182,7 @@ bool video_buffer_wait_for_open_slot(video_buffer_t *video_buffer);
* @video_buffer : video buffer.
*
* Blocks until finished slot is available.
*
*
* Returns true if the buffers next slot is finished and a
* context available.
*/
@@ -190,7 +192,7 @@ bool video_buffer_wait_for_finished_slot(video_buffer_t *video_buffer);
* bool video_buffer_has_open_slot(video_buffer_t *video_buffer)
:
* @video_buffer : video buffer.
*
*
* Returns true if the buffer has a open slot available.
*/
bool video_buffer_has_open_slot(video_buffer_t *video_buffer);
-17
View File
@@ -1,17 +0,0 @@
gong.so: gong.c
gcc \
-std=c89 \
-pedantic \
-Wall \
-Wno-unused-variable \
-g \
gong.c \
-I../../libretro-common/include/ \
-shared \
-fPIC \
-Wl,--no-undefined \
-lm \
-o gong.so
clean:
rm -f gong.so
-939
View File
@@ -1,939 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2016-2019 - Brad Parker
*
* RetroArch 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 Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
/* Libretro port by Brad Parker,
Original source code by Dan Zaidan: https://danzaidan.itch.io/
Original license:
"You can do whatever you want with the code, but I am providing it as is without any warranty whatsoever."
*/
#include <stdlib.h>
#include <string.h>
#include <libretro.h>
#include <retro_math.h>
#include <retro_inline.h>
#include <retro_endianness.h>
#ifdef RARCH_INTERNAL
#include "internal_cores.h"
#define GONG_CORE_PREFIX(s) libretro_gong_##s
#else
#define GONG_CORE_PREFIX(s) s
#endif
#define WIDTH 356
#define HEIGHT 200
#define MAX_PLAYERS 2
#define STATE_SIZE 4096 /* can be anything as long as it's large enough to hold everything */
static retro_log_printf_t GONG_CORE_PREFIX(log_cb);
static retro_video_refresh_t GONG_CORE_PREFIX(video_cb);
static retro_input_poll_t GONG_CORE_PREFIX(input_poll_cb);
static retro_input_state_t GONG_CORE_PREFIX(input_state_cb);
static retro_audio_sample_t GONG_CORE_PREFIX(audio_cb);
static retro_audio_sample_batch_t GONG_CORE_PREFIX(audio_batch_cb);
static retro_environment_t GONG_CORE_PREFIX(environ_cb);
static const char *GONG_CORE_PREFIX(valid_extensions) = "gong";
static unsigned char *video_buf = NULL;
enum
{
B_MOVE_UP,
B_MOVE_DOWN,
B_SPEED_UP,
B_COUNT /* This should always be in the bottom */
};
/* any changes here must be handled in serialization code too */
typedef struct
{
union { float f; unsigned u; } py;
union { float f; unsigned u; } dpy;
} Player;
/* any changes here must be handled in serialization code too */
typedef struct
{
int half_transition_count;
bool ended_down;
} Game_Button_State;
/* any changes here must be handled in serialization code too */
typedef struct
{
Game_Button_State buttons[B_COUNT];
float last_dt; /* not in savestate */
} Game_Input;
typedef struct
{
uint16_t input;
uint16_t not_input;
uint16_t realinput;
int16_t analogYLeft;
int16_t analogYRight;
} retro_inputs;
/* any changes here must be handled in serialization code too */
typedef struct
{
unsigned version;
unsigned player1_score;
unsigned player2_score;
union { float f; unsigned u; } player2_speed;
union { float f; unsigned u; } ball_px;
union { float f; unsigned u; } ball_py;
union { float f; unsigned u; } ball_dpx;
union { float f; unsigned u; } ball_dpy;
union { float f; unsigned u; } ball_speed;
union { float f; unsigned u; } current_play_points;
float refresh; /* not in savestate */
bool is_initialized;
bool player2_human;
uint16_t previnput[MAX_PLAYERS];
Game_Input g_input[MAX_PLAYERS];
Player player[MAX_PLAYERS];
} State;
typedef struct
{
/* Pixels are always 32-bit wide, memory order XX BB GG RR */
int width;
int height;
int pitch;
void *memory;
} Game_Offscreen_Buffer;
static State *g_state = NULL;
static Game_Offscreen_Buffer game_buffer = {0};
static void game_update_and_render(Game_Input *input, Game_Offscreen_Buffer *draw_buffer);
static const struct retro_controller_description pads1[] = {
{ "Joypad", RETRO_DEVICE_JOYPAD },
{ NULL, 0 },
};
static const struct retro_controller_description pads2[] = {
{ "Joypad", RETRO_DEVICE_JOYPAD },
{ NULL, 0 },
};
static const struct retro_controller_info ports[] = {
{ pads1, 1 },
{ pads2, 1 },
{ 0 },
};
struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 0 },
};
static void check_variables(void)
{
struct retro_variable var = {0};
var.key = "gong_refresh";
if (GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
int i;
g_state->refresh = atoi(var.value);
for (i = 0; i < (int)(sizeof(g_state->g_input) / sizeof(g_state->g_input[0])); i++)
g_state->g_input[i].last_dt = 1.0f / g_state->refresh;
}
var.key = "gong_player2";
if (GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (!strncmp(var.value, "CPU", 3))
g_state->player2_human = false;
else if (!strncmp(var.value, "Human", 5))
g_state->player2_human = true;
}
}
static void save_state(void *data, size_t size)
{
int i = 0;
int j = 0;
unsigned char *buf = (unsigned char*)data;
unsigned version = swap_if_little32(g_state->version);
unsigned player1_score = swap_if_little32(g_state->player1_score);
unsigned player2_score = swap_if_little32(g_state->player2_score);
unsigned player2_speed = swap_if_little32(g_state->player2_speed.u);
unsigned ball_px = swap_if_little32(g_state->ball_px.u);
unsigned ball_py = swap_if_little32(g_state->ball_py.u);
unsigned ball_dpx = swap_if_little32(g_state->ball_dpx.u);
unsigned ball_dpy = swap_if_little32(g_state->ball_dpy.u);
unsigned ball_speed = swap_if_little32(g_state->ball_speed.u);
unsigned current_play_points = swap_if_little32(g_state->current_play_points.u);
unsigned is_initialized = g_state->is_initialized;
unsigned player2_human = g_state->player2_human;
(void)size;
memcpy(buf, &version, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &player1_score, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &player2_score, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &player2_speed, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &ball_px, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &ball_py, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &ball_dpx, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &ball_dpy, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &ball_speed, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &current_play_points, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &is_initialized, sizeof(unsigned));
buf += sizeof(unsigned);
memcpy(buf, &player2_human, sizeof(unsigned));
buf += sizeof(unsigned);
/* previnput */
for (i = 0; i < MAX_PLAYERS; i++)
{
uint16_t previnput = swap_if_little16(g_state->previnput[i]);
memcpy(buf, &previnput, sizeof(uint16_t));
buf += sizeof(uint16_t);
}
/* g_input */
for (i = 0; i < MAX_PLAYERS; i++)
{
for (j = 0; j < B_COUNT; j++)
{
int half_transition_count = swap_if_little32(g_state->g_input[i].buttons[j].half_transition_count);
unsigned ended_down = g_state->g_input[i].buttons[j].ended_down;
memcpy(buf, &half_transition_count, sizeof(int));
buf += sizeof(int);
memcpy(buf, &ended_down, sizeof(unsigned));
buf += sizeof(unsigned);
}
}
/* player */
for (i = 0; i < MAX_PLAYERS; i++)
{
unsigned py = swap_if_little32((unsigned)g_state->player[i].py.u);
memcpy(buf, &py, sizeof(unsigned));
buf += sizeof(uint16_t);
}
}
static void load_state(const void *data, size_t size)
{
int i = 0;
int j = 0;
const unsigned char *buf = (const unsigned char*)data;
(void)size;
memset(g_state, 0, sizeof(*g_state));
g_state->version = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->player1_score = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->player2_score = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->player2_speed.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->ball_px.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->ball_py.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->ball_dpx.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->ball_dpy.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->ball_speed.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->current_play_points.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->is_initialized = (bool)swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->player2_human = (bool)swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
/* previnput */
for (i = 0; i < MAX_PLAYERS; i++)
{
uint16_t previnput = swap_if_little16(*(uint16_t*)buf);
g_state->previnput[i] = previnput;
buf += sizeof(uint16_t);
}
/* g_input */
for (i = 0; i < MAX_PLAYERS; i++)
{
for (j = 0; j < B_COUNT; j++)
{
int half_transition_count;
bool ended_down;
half_transition_count = (int)swap_if_little32(*(unsigned*)buf);
g_state->g_input[i].buttons[j].half_transition_count = half_transition_count;
buf += sizeof(int);
ended_down = (bool)swap_if_little32(*(unsigned*)buf);
g_state->g_input[i].buttons[j].ended_down = ended_down;
buf += sizeof(unsigned);
}
}
/* player */
for (i = 0; i < MAX_PLAYERS; i++)
{
g_state->player[i].py.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
g_state->player[i].dpy.u = swap_if_little32(*(unsigned*)buf);
buf += sizeof(unsigned);
}
check_variables();
}
static INLINE bool is_down(Game_Button_State state)
{
return state.ended_down;
}
void GONG_CORE_PREFIX(retro_get_system_info)(struct retro_system_info *info)
{
info->library_name = "gong";
info->library_version = "v1.0";
info->need_fullpath = false;
info->block_extract = false;
info->valid_extensions = GONG_CORE_PREFIX(valid_extensions);
}
void GONG_CORE_PREFIX(retro_get_system_av_info)(struct retro_system_av_info *info)
{
info->geometry.base_width = WIDTH;
info->geometry.base_height = HEIGHT;
info->geometry.max_width = WIDTH;
info->geometry.max_height = HEIGHT;
info->geometry.aspect_ratio = 16.0f / 9.0f;
info->timing.fps = g_state->refresh;
info->timing.sample_rate = 44100.0;
}
void GONG_CORE_PREFIX(retro_init)(void)
{
struct retro_log_callback log;
g_state = (State*)calloc(1, sizeof(*g_state));
if (GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
GONG_CORE_PREFIX(log_cb) = log.log;
else
GONG_CORE_PREFIX(log_cb) = NULL;
video_buf = (unsigned char*)calloc(1, WIDTH * HEIGHT * sizeof(unsigned));
game_buffer.width = WIDTH;
game_buffer.height = HEIGHT;
game_buffer.pitch = WIDTH * sizeof(unsigned);
game_buffer.memory = video_buf;
}
void GONG_CORE_PREFIX(retro_deinit)(void)
{
if (video_buf)
free(video_buf);
video_buf = NULL;
game_buffer.memory = NULL;
if (g_state)
free(g_state);
}
void GONG_CORE_PREFIX(retro_set_environment)(retro_environment_t cb)
{
bool no_content = true;
static const struct retro_variable vars[] = {
{ "gong_player2", "Player 2; CPU|Human" },
{ "gong_refresh", "Video Refresh Rate (restart); 60|70|72|75|100|119|120|140|144" },
{ NULL, NULL },
};
GONG_CORE_PREFIX(environ_cb) = cb;
cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_content);
cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
}
void GONG_CORE_PREFIX(retro_set_video_refresh)(retro_video_refresh_t cb)
{
GONG_CORE_PREFIX(video_cb) = cb;
}
void GONG_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t cb)
{
GONG_CORE_PREFIX(audio_cb) = cb;
}
void GONG_CORE_PREFIX(retro_set_audio_sample_batch)(retro_audio_sample_batch_t cb)
{
GONG_CORE_PREFIX(audio_batch_cb) = cb;
}
void GONG_CORE_PREFIX(retro_set_input_poll)(retro_input_poll_t cb)
{
GONG_CORE_PREFIX(input_poll_cb) = cb;
}
void GONG_CORE_PREFIX(retro_set_input_state)(retro_input_state_t cb)
{
GONG_CORE_PREFIX(input_state_cb) = cb;
}
void GONG_CORE_PREFIX(retro_set_controller_port_device)(unsigned a, unsigned b)
{
}
void GONG_CORE_PREFIX(retro_reset)(void)
{
memset(g_state, 0, sizeof(*g_state));
check_variables();
}
size_t GONG_CORE_PREFIX(retro_serialize_size)(void)
{
return STATE_SIZE;
}
bool GONG_CORE_PREFIX(retro_serialize)(void *data, size_t size)
{
if (size != STATE_SIZE)
return false;
save_state(data, size);
return true;
}
bool GONG_CORE_PREFIX(retro_unserialize)(const void *data, size_t size)
{
if (size != STATE_SIZE)
return false;
load_state(data, size);
return true;
}
void GONG_CORE_PREFIX(retro_cheat_reset)(void)
{
}
void GONG_CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char * c)
{
}
bool GONG_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info)
{
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
check_variables();
if (!GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
{
if (GONG_CORE_PREFIX(log_cb))
GONG_CORE_PREFIX(log_cb)(RETRO_LOG_INFO, "XRGB8888 is not supported.\n");
return false;
}
return true;
}
bool GONG_CORE_PREFIX(retro_load_game_special)(unsigned a, const struct retro_game_info *b, size_t c)
{
return false;
}
void GONG_CORE_PREFIX(retro_unload_game)(void)
{
}
unsigned GONG_CORE_PREFIX(retro_get_region)(void)
{
return RETRO_REGION_NTSC;
}
void* GONG_CORE_PREFIX(retro_get_memory_data)(unsigned id)
{
return NULL;
}
size_t GONG_CORE_PREFIX(retro_get_memory_size)(unsigned id)
{
return 0;
}
static void process_joypad(Game_Button_State *new_state, bool is_down)
{
if (new_state->ended_down != is_down)
{
new_state->ended_down = is_down;
new_state->half_transition_count += 1;
}
}
static bool is_key_up_or_down(int16_t input, int16_t not_input, int key)
{
if (input & (1 << key) || not_input & (1 << key))
return true;
return false;
}
void GONG_CORE_PREFIX(retro_run)(void)
{
int i = 0;
int port = 0;
bool updated = false;
retro_inputs inputs[MAX_PLAYERS] = {{0}};
if (GONG_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
check_variables();
GONG_CORE_PREFIX(input_poll_cb)();
for (port = 0; port < MAX_PLAYERS; port++)
{
for (i = 0; i < 16; i++)
{
if (GONG_CORE_PREFIX(input_state_cb)(port, RETRO_DEVICE_JOYPAD, 0, i))
{
inputs[port].realinput |= 1 << i;
}
}
inputs[port].analogYLeft = GONG_CORE_PREFIX(input_state_cb)(port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 5000.0f;
inputs[port].analogYRight = GONG_CORE_PREFIX(input_state_cb)(port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / 5000.0f;
if (inputs[port].analogYLeft > 0)
inputs[port].realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_DOWN);
else if (inputs[port].analogYRight > 0)
inputs[port].realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_DOWN);
if (inputs[port].analogYLeft < 0)
inputs[port].realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_UP);
else if (inputs[port].analogYRight < 0)
inputs[port].realinput |= (1 << RETRO_DEVICE_ID_JOYPAD_UP);
inputs[port].input = inputs[port].realinput & ~g_state->previnput[port];
inputs[port].not_input = g_state->previnput[port] & ~inputs[port].realinput;
if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_UP))
process_joypad(&g_state->g_input[port].buttons[B_MOVE_UP], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_UP));
else if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
process_joypad(&g_state->g_input[port].buttons[B_MOVE_DOWN], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN));
else if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
process_joypad(&g_state->g_input[port].buttons[B_MOVE_DOWN], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN));
if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_A))
process_joypad(&g_state->g_input[port].buttons[B_SPEED_UP], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_A));
else if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_B))
process_joypad(&g_state->g_input[port].buttons[B_SPEED_UP], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_B));
else if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_X))
process_joypad(&g_state->g_input[port].buttons[B_SPEED_UP], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_X));
else if (is_key_up_or_down(inputs[port].input, inputs[port].not_input, RETRO_DEVICE_ID_JOYPAD_Y))
process_joypad(&g_state->g_input[port].buttons[B_SPEED_UP], inputs[port].realinput & (1 << RETRO_DEVICE_ID_JOYPAD_Y));
g_state->previnput[port] = inputs[port].realinput;
}
game_update_and_render(g_state->g_input, &game_buffer);
GONG_CORE_PREFIX(video_cb)(video_buf, WIDTH, HEIGHT, WIDTH * sizeof(uint32_t));
}
unsigned GONG_CORE_PREFIX(retro_api_version)(void)
{
return RETRO_API_VERSION;
}
static void draw_rect_in_pixels(Game_Offscreen_Buffer *buffer, unsigned color, int min_x, int min_y, int max_x, int max_y)
{
int y;
min_x = MAX(min_x, 0);
min_y = MAX(min_y, 0);
max_x = MIN(max_x, buffer->width);
max_y = MIN(max_y, buffer->height);
for (y = min_y; y < max_y; y++)
{
int x;
for (x = min_x; x < max_x; x++)
{
unsigned *pixel = (unsigned*)((unsigned char*)buffer->memory + ((buffer->width * (buffer->height - y - 1) + x) * sizeof(unsigned)));
*pixel++ = color;
}
}
}
static void clear(Game_Offscreen_Buffer *buffer, unsigned color)
{
draw_rect_in_pixels(buffer, color, 0, 0, buffer->width, buffer->height);
}
static void draw_rect(Game_Offscreen_Buffer *buffer, unsigned color, float x, float y, float half_size_x, float half_size_y)
{
/* @Hardcoded to always keep the playing field area on screen, no matter the aspect ratio */
float scale = .01f;
float relative_axis = (float)buffer->height;
int min_x, min_y, max_x, max_y;
if ((float)buffer->width / (float)buffer->height < 1.77f)
{
relative_axis = (float)buffer->width;
scale = .0056f;
}
half_size_x *= relative_axis * scale;
half_size_y *= relative_axis * scale;
x *= relative_axis * scale;
y *= relative_axis * scale;
x = x + buffer->width / 2;
y = y + buffer->height / 2;
min_x = (unsigned)(x - half_size_x);
min_y = (unsigned)(y - half_size_y);
max_x = (unsigned)(x + half_size_x);
max_y = (unsigned)(y + half_size_y);
draw_rect_in_pixels(buffer, color, min_x, min_y, max_x, max_y);
}
static void draw_number(Game_Offscreen_Buffer *buffer, unsigned number, unsigned color, float x, float y)
{
float at_x = x;
do {
unsigned alg = number % 10;
number /= 10;
switch (alg)
{
case 0:
{
draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
}
case 1:
{
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f);
break;
}
case 2:
{
draw_rect(buffer, color, at_x - 2.f, y - 2.f, .5f, 2.f);
draw_rect(buffer, color, at_x + 2.f, y + 2.f, .5f, 2.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
}
case 3:
{
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
};
case 4:
{
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f);
draw_rect(buffer, color, at_x - 2.f, y+2.5f, .5f, 2.f);
break;
};
case 5:
{
draw_rect(buffer, color, at_x + 2.f, y-2.f, .5f, 2.f);
draw_rect(buffer, color, at_x - 2.f, y+2.f, .5f, 2.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
};
case 6:
{
draw_rect(buffer, color, at_x + 2.f, y-2.f, .5f, 2.f);
draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
};
case 7:
{
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.5f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
break;
};
case 8:
{
draw_rect(buffer, color, at_x - 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
break;
};
case 9:
{
draw_rect(buffer, color, at_x - 2.f, y + 2.f, .5f, 2.f);
draw_rect(buffer, color, at_x + 2.f, y, .5f, 4.f);
draw_rect(buffer, color, at_x, y + 4.f, 2.5f, .5f);
draw_rect(buffer, color, at_x, y, 2.5f, .5f);
draw_rect(buffer, color, at_x, y - 4.f, 2.5f, .5f);
break;
};
default:
break;
}
at_x -= 7.f;
} while(number > 0);
}
static void game_update_and_render(Game_Input *input, Game_Offscreen_Buffer *draw_buffer)
{
const float initial_ball_speed = 80.f;
float playing_field_x = 85.f;
float playing_field_y = 48.f;
float player_size_x = 2.5f;
float player_size_y = 10.f;
int i;
if (!g_state->is_initialized)
{
g_state->is_initialized = 1;
g_state->ball_px.f = 0;
g_state->ball_py.f = 0;
g_state->ball_dpx.f = initial_ball_speed;
g_state->ball_dpy.f = 0;
g_state->current_play_points.f = 10.f;
g_state->player2_speed.f = 80.f;
}
for (i = 0; i < MAX_PLAYERS; i++)
{
float speed = 80.f;
if (i == 1 && !g_state->player2_human)
break;
g_state->player[i].dpy.f = 0.f;
if (is_down(input[i].buttons[B_SPEED_UP]))
speed = 150.f;
if (is_down(input[i].buttons[B_MOVE_UP]))
{
if (g_state->player[i].py.f < playing_field_y - player_size_y)
{
g_state->player[i].dpy.f = speed;
}
if (g_state->player[i].py.f < -playing_field_y + player_size_y)
{
g_state->player[i].py.f = -playing_field_y + player_size_y;
g_state->player[i].dpy.f = 0.f;
}
}
if (is_down(input[i].buttons[B_MOVE_DOWN]))
{
if (g_state->player[i].py.f > -playing_field_y + player_size_y)
{
g_state->player[i].dpy.f = -speed;
}
if (g_state->player[i].py.f < -playing_field_y + player_size_y)
{
g_state->player[i].py.f = -playing_field_y + player_size_y;
g_state->player[i].dpy.f = 0.f;
}
}
g_state->player[i].py.f += g_state->player[i].dpy.f * input->last_dt;
}
if (!g_state->player2_human)
{
g_state->player[1].dpy.f = (g_state->ball_py.f - g_state->player[1].py.f) * 100.f;
g_state->player[1].dpy.f = MIN(g_state->player[1].dpy.f, g_state->player2_speed.f);
g_state->player[1].dpy.f = MAX(g_state->player[1].dpy.f, -g_state->player2_speed.f);
g_state->player[1].py.f += g_state->player[1].dpy.f * input->last_dt;
if (g_state->player[1].py.f < -playing_field_y + player_size_y)
{
g_state->player[1].py.f = -playing_field_y + player_size_y;
g_state->player[1].dpy.f = 0.f;
}
if (g_state->player[1].py.f > playing_field_y - player_size_y)
{
g_state->player[1].py.f = playing_field_y - player_size_y;
g_state->player[1].dpy.f = 0.f;
}
}
g_state->ball_px.f += g_state->ball_dpx.f * input->last_dt;
if (g_state->ball_dpx.f > 0)
{
g_state->ball_dpx.f += 10.f * input->last_dt;
}
else
{
g_state->ball_dpx.f -= 10.f * input->last_dt;
}
g_state->ball_py.f += g_state->ball_dpy.f * input->last_dt;
if (g_state->ball_py.f > playing_field_y - 1.f)
{
g_state->ball_py.f = playing_field_y - 1.f;
g_state->ball_dpy.f *= -1.f;
}
else if (g_state->ball_py.f < -playing_field_y + 1)
{
g_state->ball_py.f = -playing_field_y + 1.f;
g_state->ball_dpy.f *= -1;
}
if (g_state->ball_px.f > 80.f - 2.5f - 1.f) /* @Hardcoded */
{
if ((g_state->ball_py.f >= (g_state->player[1].py.f - 10.f)) && (g_state->ball_py.f <= (g_state->player[1].py.f + 10.f)))
{
g_state->ball_dpx.f *= -1.f;
g_state->ball_px.f = 80.f - 2.5f - 1.f; /* @Hardcoded */
g_state->ball_dpy.f = (g_state->ball_py.f - g_state->player[1].py.f) + g_state->player[1].dpy.f;
++g_state->current_play_points.f;
}
else if (g_state->ball_px.f >= playing_field_x - 1)
{
g_state->ball_px.f = 0;
g_state->ball_py.f = 0;
g_state->ball_dpy.f = 0;
g_state->ball_dpx.f = -initial_ball_speed;
g_state->player2_score += (unsigned)g_state->current_play_points.f;
g_state->current_play_points.f = 10.f;
}
}
else if (g_state->ball_px.f < -80 + 2.5f + 1.f) /* @Hardcoded */
{
if ((g_state->ball_py.f >= (g_state->player[0].py.f - 10.f)) && (g_state->ball_py.f <= (g_state->player[0].py.f + 10.f)))
{
g_state->ball_dpx.f *= -1.f;
g_state->ball_px.f = -80 + 2.5f + 1.f; /* @Hardcoded */
g_state->ball_dpy.f = (g_state->ball_py.f - g_state->player[0].py.f) + g_state->player[0].dpy.f;
++g_state->current_play_points.f;
}
else if (g_state->ball_px.f <= -playing_field_x + 1)
{
g_state->ball_px.f = 0;
g_state->ball_py.f = 0;
g_state->ball_dpy.f = 0;
g_state->ball_dpx.f = initial_ball_speed;
g_state->player1_score += (unsigned)g_state->current_play_points.f;
g_state->current_play_points.f = 10.f;
if (!g_state->player2_human)
g_state->player2_speed.f += g_state->current_play_points.f * 0.01f;
}
}
clear(draw_buffer, 0x021077);
draw_rect(draw_buffer, 0x000530, 0.f, 0.f, playing_field_x, playing_field_y);
draw_rect(draw_buffer, 0x00ffff, -80.f, g_state->player[0].py.f, player_size_x, player_size_y);
draw_rect(draw_buffer, 0x00ffff, 80.f, g_state->player[1].py.f, player_size_x, player_size_y);
draw_rect(draw_buffer, 0xffff00, g_state->ball_px.f, g_state->ball_py.f, 1.f, 1.f);
draw_number(draw_buffer, (unsigned)g_state->current_play_points.f, 0xaaaaaa, 0.f, 38.f);
draw_number(draw_buffer, g_state->player1_score, 0xff6611, 20.f, 38.f);
draw_number(draw_buffer, g_state->player2_score, 0xff6611, -20.f, 38.f);
}
-1
View File
@@ -1 +0,0 @@
#include "../internal_cores.h"
-4
View File
@@ -1,4 +0,0 @@
{
global: retro_*;
local: *;
};
+171 -1
View File
@@ -209,6 +209,76 @@ static int database_cursor_iterate(libretrodb_cursor_t *cur,
if (!string_is_empty(val_string))
db_info->genre = strdup(val_string);
}
else if (string_is_equal(str, "category"))
{
if (!string_is_empty(val_string))
db_info->category = strdup(val_string);
}
else if (string_is_equal(str, "language"))
{
if (!string_is_empty(val_string))
db_info->language = strdup(val_string);
}
else if (string_is_equal(str, "region"))
{
if (!string_is_empty(val_string))
db_info->region = strdup(val_string);
}
else if (string_is_equal(str, "score"))
{
if (!string_is_empty(val_string))
db_info->score = strdup(val_string);
}
else if (string_is_equal(str, "media"))
{
if (!string_is_empty(val_string))
db_info->media = strdup(val_string);
}
else if (string_is_equal(str, "controls"))
{
if (!string_is_empty(val_string))
db_info->controls = strdup(val_string);
}
else if (string_is_equal(str, "artstyle"))
{
if (!string_is_empty(val_string))
db_info->artstyle = strdup(val_string);
}
else if (string_is_equal(str, "gameplay"))
{
if (!string_is_empty(val_string))
db_info->gameplay = strdup(val_string);
}
else if (string_is_equal(str, "narrative"))
{
if (!string_is_empty(val_string))
db_info->narrative = strdup(val_string);
}
else if (string_is_equal(str, "pacing"))
{
if (!string_is_empty(val_string))
db_info->pacing = strdup(val_string);
}
else if (string_is_equal(str, "perspective"))
{
if (!string_is_empty(val_string))
db_info->perspective = strdup(val_string);
}
else if (string_is_equal(str, "setting"))
{
if (!string_is_empty(val_string))
db_info->setting = strdup(val_string);
}
else if (string_is_equal(str, "visual"))
{
if (!string_is_empty(val_string))
db_info->visual = strdup(val_string);
}
else if (string_is_equal(str, "vehicular"))
{
if (!string_is_empty(val_string))
db_info->vehicular = strdup(val_string);
}
else if (string_is_equal(str, "origin"))
{
if (!string_is_empty(val_string))
@@ -274,6 +344,12 @@ static int database_cursor_iterate(libretrodb_cursor_t *cur,
db_info->releaseyear = (unsigned)val->val.uint_;
else if (string_is_equal(str, "rumble"))
db_info->rumble_supported = (int)val->val.uint_;
else if (string_is_equal(str, "achievements"))
db_info->achievements = (int)val->val.uint_;
else if (string_is_equal(str, "console_exclusive"))
db_info->console_exclusive = (int)val->val.uint_;
else if (string_is_equal(str, "platform_exclusive"))
db_info->platform_exclusive = (int)val->val.uint_;
else if (string_is_equal(str, "coop"))
db_info->coop_supported = (int)val->val.uint_;
else if (string_is_equal(str, "analog"))
@@ -504,6 +580,34 @@ database_info_list_t *database_info_list_new(
free(db_info.franchise);
if (db_info.genre)
free(db_info.genre);
if (db_info.category)
free(db_info.category);
if (db_info.language)
free(db_info.language);
if (db_info.region)
free(db_info.region);
if (db_info.score)
free(db_info.score);
if (db_info.media)
free(db_info.media);
if (db_info.controls)
free(db_info.controls);
if (db_info.artstyle)
free(db_info.artstyle);
if (db_info.gameplay)
free(db_info.gameplay);
if (db_info.narrative)
free(db_info.narrative);
if (db_info.pacing)
free(db_info.pacing);
if (db_info.perspective)
free(db_info.perspective);
if (db_info.setting)
free(db_info.setting);
if (db_info.visual)
free(db_info.visual);
if (db_info.vehicular)
free(db_info.vehicular);
if (db_info.name)
free(db_info.name);
if (db_info.origin)
@@ -520,6 +624,26 @@ database_info_list_t *database_info_list_new(
free(db_info.md5);
if (db_info.sha1)
free(db_info.sha1);
db_info.name = NULL;
db_info.rom_name = NULL;
db_info.serial = NULL;
db_info.genre = NULL;
db_info.description = NULL;
db_info.publisher = NULL;
db_info.developer = NULL;
db_info.origin = NULL;
db_info.franchise = NULL;
db_info.edge_magazine_review = NULL;
db_info.cero_rating = NULL;
db_info.pegi_rating = NULL;
db_info.enhancement_hw = NULL;
db_info.elspa_rating = NULL;
db_info.esrb_rating = NULL;
db_info.bbfc_rating = NULL;
db_info.sha1 = NULL;
db_info.md5 = NULL;
database_info_list_free(database_info_list);
free(database_info);
free(database_info_list);
@@ -570,13 +694,40 @@ void database_info_list_free(database_info_list_t *database_info_list)
free(info->serial);
if (info->genre)
free(info->genre);
if (info->category)
free(info->category);
if (info->language)
free(info->language);
if (info->region)
free(info->region);
if (info->score)
free(info->score);
if (info->media)
free(info->media);
if (info->controls)
free(info->controls);
if (info->artstyle)
free(info->artstyle);
if (info->gameplay)
free(info->gameplay);
if (info->narrative)
free(info->narrative);
if (info->pacing)
free(info->pacing);
if (info->perspective)
free(info->perspective);
if (info->setting)
free(info->setting);
if (info->visual)
free(info->visual);
if (info->vehicular)
free(info->vehicular);
if (info->description)
free(info->description);
if (info->publisher)
free(info->publisher);
if (info->developer)
string_list_free(info->developer);
info->developer = NULL;
if (info->origin)
free(info->origin);
if (info->franchise)
@@ -600,6 +751,25 @@ void database_info_list_free(database_info_list_t *database_info_list)
free(info->sha1);
if (info->md5)
free(info->md5);
info->name = NULL;
info->rom_name = NULL;
info->serial = NULL;
info->genre = NULL;
info->description = NULL;
info->publisher = NULL;
info->developer = NULL;
info->origin = NULL;
info->franchise = NULL;
info->edge_magazine_review = NULL;
info->cero_rating = NULL;
info->pegi_rating = NULL;
info->enhancement_hw = NULL;
info->elspa_rating = NULL;
info->esrb_rating = NULL;
info->bbfc_rating = NULL;
info->sha1 = NULL;
info->md5 = NULL;
}
free(database_info_list->list);
+17
View File
@@ -85,6 +85,23 @@ typedef struct
char *serial;
char *description;
char *genre;
int achievements;
char *category;
char *language;
char *region;
int console_exclusive;
int platform_exclusive;
char *score;
char *media;
char *controls;
char *artstyle;
char *gameplay;
char *narrative;
char *pacing;
char *perspective;
char *setting;
char *visual;
char *vehicular;
char *publisher;
struct string_list *developer;
char *origin;
+2 -3
View File
@@ -212,9 +212,8 @@ WRes File_Seek(CSzFile *p, int64_t *pos, ESzSeek origin)
WRes File_GetLength(CSzFile *p, uint64_t *length)
{
#ifdef USE_WINDOWS_FILE
DWORD sizeHigh;
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
DWORD sizeHigh = 0;
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
if (sizeLow == 0xFFFFFFFF)
{
DWORD res = GetLastError();
+7
View File
@@ -88,6 +88,10 @@ typedef struct rc_api_leaderboard_definition_t {
const char* description;
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
const char* definition;
/* Non-zero if lower values are better for this leaderboard */
int lower_is_better;
/* Non-zero if the leaderboard should not be displayed in a list of leaderboards */
int hidden;
}
rc_api_leaderboard_definition_t;
@@ -210,6 +214,9 @@ typedef struct rc_api_award_achievement_response_t {
unsigned awarded_achievement_id;
/* The updated player score */
unsigned new_player_score;
/* The number of achievements the user has not yet unlocked for this game
* (in hardcore/non-hardcore per hardcore flag in request) */
unsigned achievements_remaining;
/* Common server-provided response information */
rc_api_response_t response;
+2
View File
@@ -35,6 +35,8 @@ typedef struct rc_api_login_response_t {
unsigned score;
/* The number of unread messages waiting for the player on the web site */
unsigned num_unread_messages;
/* The preferred name to display for the player */
const char* display_name;
/* Common server-provided response information */
rc_api_response_t response;
+5
View File
@@ -76,6 +76,11 @@ enum {
RC_CONSOLE_SHARPX1 = 64,
RC_CONSOLE_TIC80 = 65,
RC_CONSOLE_THOMSONTO8 = 66,
RC_CONSOLE_PC6000 = 67,
RC_CONSOLE_PICO = 68,
RC_CONSOLE_MEGADUCK = 69,
RC_CONSOLE_ZEEBO = 70,
RC_CONSOLE_ARDUBOY = 71,
RC_CONSOLE_HUBS = 100,
RC_CONSOLE_EVENTS = 101
+5 -4
View File
@@ -101,7 +101,7 @@ extern "C" {
*/
typedef void* (*rc_hash_cdreader_open_track_handler)(const char* path, uint32_t track);
/* attempts to read the specified number of bytes from the file starting at the read pointer.
/* attempts to read the specified number of bytes from the file starting at the specified absolute sector.
* returns the number of bytes actually read.
*/
typedef size_t (*rc_hash_cdreader_read_sector_handler)(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes);
@@ -109,17 +109,18 @@ extern "C" {
/* closes the track handle */
typedef void (*rc_hash_cdreader_close_track_handler)(void* track_handle);
/* convert absolute sector to track sector */
typedef uint32_t(*rc_hash_cdreader_absolute_sector_to_track_sector)(void* track_handle, uint32_t sector);
/* gets the absolute sector index for the first sector of a track */
typedef uint32_t(*rc_hash_cdreader_first_track_sector_handler)(void* track_handle);
struct rc_hash_cdreader
{
rc_hash_cdreader_open_track_handler open_track;
rc_hash_cdreader_read_sector_handler read_sector;
rc_hash_cdreader_close_track_handler close_track;
rc_hash_cdreader_absolute_sector_to_track_sector absolute_sector_to_track_sector;
rc_hash_cdreader_first_track_sector_handler first_track_sector;
};
void rc_hash_get_default_cdreader(struct rc_hash_cdreader* cdreader);
void rc_hash_init_default_cdreader(void);
void rc_hash_init_custom_cdreader(struct rc_hash_cdreader* reader);
+2
View File
@@ -58,6 +58,7 @@ typedef struct rc_runtime_lboard_t {
void* buffer;
rc_memref_t* invalid_memref;
unsigned char md5[16];
int serialized_size;
char owns_memrefs;
}
rc_runtime_lboard_t;
@@ -66,6 +67,7 @@ typedef struct rc_runtime_richpresence_t {
rc_richpresence_t* richpresence;
void* buffer;
struct rc_runtime_richpresence_t* previous;
unsigned char md5[16];
char owns_memrefs;
}
rc_runtime_richpresence_t;
+14 -3
View File
@@ -54,6 +54,8 @@ enum {
RC_MEMSIZE_16_BITS_BE,
RC_MEMSIZE_24_BITS_BE,
RC_MEMSIZE_32_BITS_BE,
RC_MEMSIZE_FLOAT,
RC_MEMSIZE_MBF32,
RC_MEMSIZE_VARIABLE
};
@@ -67,6 +69,8 @@ typedef struct rc_memref_value_t {
char size;
/* True if the value changed this frame. */
char changed;
/* The value type of the value (for variables) */
char type;
/* True if the reference will be used in indirection.
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
char is_indirect;
@@ -123,7 +127,7 @@ typedef struct rc_operand_t {
}
rc_operand_t;
int rc_operand_is_memref(rc_operand_t* operand);
int rc_operand_is_memref(const rc_operand_t* operand);
/*****************************************************************************\
| Conditions |
@@ -280,7 +284,7 @@ struct rc_value_t {
/* The list of conditions to evaluate. */
rc_condset_t* conditions;
/* The memory references required by the value. */
/* The memory references required by the variable. */
rc_memref_t* memrefs;
/* The name of the variable. */
@@ -337,7 +341,13 @@ enum {
RC_FORMAT_SCORE,
RC_FORMAT_VALUE,
RC_FORMAT_MINUTES,
RC_FORMAT_SECONDS_AS_MINUTES
RC_FORMAT_SECONDS_AS_MINUTES,
RC_FORMAT_FLOAT1,
RC_FORMAT_FLOAT2,
RC_FORMAT_FLOAT3,
RC_FORMAT_FLOAT4,
RC_FORMAT_FLOAT5,
RC_FORMAT_FLOAT6
};
int rc_parse_format(const char* format_str);
@@ -398,6 +408,7 @@ rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_S
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L);
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
void rc_reset_richpresence(rc_richpresence_t* self);
#ifdef __cplusplus
}
+9 -10
View File
@@ -4,8 +4,6 @@
#include "../rcheevos/rc_compat.h"
#include "../rhash/md5.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -520,6 +518,13 @@ int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_
continue;
}
if (*src == 't') {
/* tab */
++src;
*dst++ = '\t';
continue;
}
/* just an escaped character, fallthrough to normal copy */
}
@@ -631,7 +636,7 @@ int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* fi
return 1;
}
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, int default_value) {
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, unsigned default_value) {
if (!rc_json_get_unum(out, field, field_name))
*out = default_value;
}
@@ -813,13 +818,7 @@ void rc_api_destroy_request(rc_api_request_t* request) {
rc_buf_destroy(&request->buffer);
}
void rc_api_generate_checksum(char checksum[33], const char* data) {
md5_state_t md5;
md5_byte_t digest[16];
md5_init(&md5);
md5_append(&md5, (unsigned char*)data, (int)strlen(data));
md5_finish(&md5, digest);
void rc_api_format_md5(char checksum[33], const unsigned char digest[16]) {
snprintf(checksum, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
+2 -2
View File
@@ -46,7 +46,7 @@ int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_n
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name);
void rc_json_get_optional_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name, const char* default_value);
void rc_json_get_optional_num(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, int default_value);
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, unsigned default_value);
void rc_json_get_optional_bool(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
int rc_json_get_required_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_num(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
@@ -72,7 +72,7 @@ void rc_url_builder_append_str_param(rc_api_url_builder_t* builder, const char*
void rc_api_url_build_dorequest_url(rc_api_request_t* request);
int rc_api_url_build_dorequest(rc_api_url_builder_t* builder, const char* api, const char* username, const char* api_token);
void rc_api_generate_checksum(char checksum[33], const char* data);
void rc_api_format_md5(char checksum[33], const unsigned char digest[16]);
#ifdef __cplusplus
}
+35 -14
View File
@@ -4,6 +4,7 @@
#include "rc_runtime.h"
#include "rc_runtime_types.h"
#include "../rcheevos/rc_compat.h"
#include "../rhash/md5.h"
#include <stdlib.h>
#include <stdio.h>
@@ -119,14 +120,16 @@ int rc_api_process_fetch_game_data_response(rc_api_fetch_game_data_response_t* r
{"Title"},
{"Description"},
{"Mem"},
{"Format"}
{"Format"},
{"LowerIsBetter"},
{"Hidden"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
if (result != RC_OK || !response->response.succeeded)
return result;
if (!rc_json_get_required_object(patchdata_fields, sizeof(patchdata_fields) / sizeof(patchdata_fields[0]), &response->response, &fields[2], "PatchData"))
@@ -237,6 +240,8 @@ int rc_api_process_fetch_game_data_response(rc_api_fetch_game_data_response_t* r
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&leaderboard->definition, &response->response, &leaderboard_fields[3], "Mem"))
return RC_MISSING_VALUE;
rc_json_get_optional_bool(&leaderboard->lower_is_better, &leaderboard_fields[5], "LowerIsBetter", 0);
rc_json_get_optional_bool(&leaderboard->hidden, &leaderboard_fields[6], "Hidden", 0);
if (!leaderboard_fields[4].value_end)
return RC_MISSING_VALUE;
@@ -304,8 +309,9 @@ void rc_api_destroy_ping_response(rc_api_ping_response_t* response) {
int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_api_award_achievement_request_t* api_params) {
rc_api_url_builder_t builder;
char signature[128];
char checksum[33];
char buffer[33];
md5_state_t md5;
md5_byte_t digest[16];
rc_api_url_build_dorequest_url(request);
@@ -320,9 +326,15 @@ int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_ap
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
/* Evaluate the signature. */
snprintf(signature, sizeof(signature), "%u%s%u", api_params->achievement_id, api_params->username, api_params->hardcore ? 1 : 0);
rc_api_generate_checksum(checksum, signature);
rc_url_builder_append_str_param(&builder, "v", checksum);
md5_init(&md5);
snprintf(buffer, sizeof(buffer), "%u", api_params->achievement_id);
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
snprintf(buffer, sizeof(buffer), "%d", api_params->hardcore ? 1 : 0);
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
md5_finish(&md5, digest);
rc_api_format_md5(buffer, digest);
rc_url_builder_append_str_param(&builder, "v", buffer);
request->post_data = rc_url_builder_finalize(&builder);
}
@@ -336,7 +348,8 @@ int rc_api_process_award_achievement_response(rc_api_award_achievement_response_
{"Success"},
{"Error"},
{"Score"},
{"AchievementID"}
{"AchievementID"},
{"AchievementsRemaining"}
};
memset(response, 0, sizeof(*response));
@@ -361,6 +374,7 @@ int rc_api_process_award_achievement_response(rc_api_award_achievement_response_
rc_json_get_optional_unum(&response->new_player_score, &fields[2], "Score", 0);
rc_json_get_optional_unum(&response->awarded_achievement_id, &fields[3], "AchievementID", 0);
rc_json_get_optional_unum(&response->achievements_remaining, &fields[4], "AchievementsRemaining", (unsigned)-1);
return RC_OK;
}
@@ -373,8 +387,9 @@ void rc_api_destroy_award_achievement_response(rc_api_award_achievement_response
int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_api_submit_lboard_entry_request_t* api_params) {
rc_api_url_builder_t builder;
char signature[128];
char checksum[33];
char buffer[33];
md5_state_t md5;
md5_byte_t digest[16];
rc_api_url_build_dorequest_url(request);
@@ -390,9 +405,15 @@ int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
/* Evaluate the signature. */
snprintf(signature, sizeof(signature), "%u%s%d", api_params->leaderboard_id, api_params->username, api_params->score);
rc_api_generate_checksum(checksum, signature);
rc_url_builder_append_str_param(&builder, "v", checksum);
md5_init(&md5);
snprintf(buffer, sizeof(buffer), "%u", api_params->leaderboard_id);
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
snprintf(buffer, sizeof(buffer), "%d", api_params->score);
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
md5_finish(&md5, digest);
rc_api_format_md5(buffer, digest);
rc_url_builder_append_str_param(&builder, "v", buffer);
request->post_data = rc_url_builder_finalize(&builder);
}
@@ -456,7 +477,7 @@ int rc_api_process_submit_lboard_entry_response(rc_api_submit_lboard_entry_respo
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
if (result != RC_OK || !response->response.succeeded)
return result;
if (!rc_json_get_required_object(response_fields, sizeof(response_fields) / sizeof(response_fields[0]), &response->response, &fields[2], "Response"))
+5 -2
View File
@@ -37,7 +37,8 @@ int rc_api_process_login_response(rc_api_login_response_t* response, const char*
{"User"},
{"Token"},
{"Score"},
{"Messages"}
{"Messages"},
{"DisplayName"}
};
memset(response, 0, sizeof(*response));
@@ -55,6 +56,8 @@ int rc_api_process_login_response(rc_api_login_response_t* response, const char*
rc_json_get_optional_unum(&response->score, &fields[4], "Score", 0);
rc_json_get_optional_unum(&response->num_unread_messages, &fields[5], "Messages", 0);
rc_json_get_optional_string(&response->display_name, &response->response, &fields[6], "DisplayName", response->username);
return RC_OK;
}
@@ -138,7 +141,7 @@ int rc_api_process_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_respons
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
if (result != RC_OK || !response->response.succeeded)
return result;
result = rc_json_get_required_unum_array(&response->achievement_ids, &response->num_achievement_ids, &response->response, &fields[2], "UserUnlocks");
+34 -54
View File
@@ -70,6 +70,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self = RC_ALLOC(rc_condition_t, parse);
self->current_hits = 0;
self->is_true = 0;
self->pause = 0;
if (*aux != 0 && aux[1] == ':') {
switch (*aux) {
@@ -106,11 +107,6 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
return 0;
}
if (self->operand1.type == RC_OPERAND_FP) {
parse->offset = can_modify ? RC_INVALID_FP_OPERAND : RC_INVALID_COMPARISON;
return 0;
}
result = rc_parse_operator(&aux);
if (result < 0) {
parse->offset = result;
@@ -175,11 +171,6 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->operand2.value.num = 0;
}
if (!can_modify && self->operand2.type == RC_OPERAND_FP) {
parse->offset = RC_INVALID_COMPARISON;
return 0;
}
if (*aux == '(') {
char* end;
self->required_hits = (unsigned)strtoul(++aux, &end, 10);
@@ -222,63 +213,52 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
return self;
}
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
unsigned value1 = rc_evaluate_operand(&self->operand1, eval_state) + eval_state->add_value;
unsigned value2 = rc_evaluate_operand(&self->operand2, eval_state);
int rc_condition_is_combining(const rc_condition_t* self) {
switch (self->type) {
case RC_CONDITION_STANDARD:
case RC_CONDITION_PAUSE_IF:
case RC_CONDITION_RESET_IF:
case RC_CONDITION_MEASURED_IF:
case RC_CONDITION_TRIGGER:
case RC_CONDITION_MEASURED:
return 0;
switch (self->oper) {
case RC_OPERATOR_EQ: return value1 == value2;
case RC_OPERATOR_NE: return value1 != value2;
case RC_OPERATOR_LT: return value1 < value2;
case RC_OPERATOR_LE: return value1 <= value2;
case RC_OPERATOR_GT: return value1 > value2;
case RC_OPERATOR_GE: return value1 >= value2;
case RC_OPERATOR_NONE: return 1;
default: return 1;
default:
return 1;
}
}
int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_state) {
unsigned value = rc_evaluate_operand(&self->operand1, eval_state);
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
rc_typed_value_t value1, value2;
rc_evaluate_operand(&value1, &self->operand1, eval_state);
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE)
rc_typed_value_add(&value1, &eval_state->add_value);
rc_evaluate_operand(&value2, &self->operand2, eval_state);
return rc_typed_value_compare(&value1, &value2, self->oper);
}
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state) {
rc_typed_value_t amount;
rc_evaluate_operand(value, &self->operand1, eval_state);
rc_evaluate_operand(&amount, &self->operand2, eval_state);
switch (self->oper) {
case RC_OPERATOR_MULT:
if (self->operand2.type == RC_OPERAND_FP) {
value = (int)((double)value * self->operand2.value.dbl);
}
else {
/* the c standard for unsigned multiplication is well defined as non-overflowing truncation
* to the type's size. this allows negative multiplication through twos-complements. i.e.
* 1 * -1 (0xFFFFFFFF) = 0xFFFFFFFF = -1
* 3 * -2 (0xFFFFFFFE) = 0x2FFFFFFFA & 0xFFFFFFFF = 0xFFFFFFFA = -6
* 10 * -5 (0xFFFFFFFB) = 0x9FFFFFFCE & 0xFFFFFFFF = 0xFFFFFFCE = -50
*/
value *= rc_evaluate_operand(&self->operand2, eval_state);
}
rc_typed_value_multiply(value, &amount);
break;
case RC_OPERATOR_DIV:
if (self->operand2.type == RC_OPERAND_FP)
{
if (self->operand2.value.dbl == 0.0)
value = 0;
else
value = (int)((double)value / self->operand2.value.dbl);
}
else
{
unsigned value2 = rc_evaluate_operand(&self->operand2, eval_state);
if (value2 == 0)
value = 0;
else
value /= value2;
}
rc_typed_value_divide(value, &amount);
break;
case RC_OPERATOR_AND:
value &= rc_evaluate_operand(&self->operand2, eval_state);
rc_typed_value_convert(value, RC_VALUE_TYPE_UNSIGNED);
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 &= amount.value.u32;
break;
}
return value;
}
+80 -47
View File
@@ -1,36 +1,32 @@
#include "rc_internal.h"
static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause) {
if (condition->next != 0) {
rc_update_condition_pause(condition->next, in_pause);
}
#include <string.h> /* memcpy */
switch (condition->type) {
case RC_CONDITION_PAUSE_IF:
*in_pause = condition->pause = 1;
break;
static void rc_update_condition_pause(rc_condition_t* condition) {
rc_condition_t* subclause = condition;
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_SUB_HITS:
case RC_CONDITION_AND_NEXT:
case RC_CONDITION_OR_NEXT:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_RESET_NEXT_IF:
condition->pause = (char)*in_pause;
break;
while (condition) {
if (condition->type == RC_CONDITION_PAUSE_IF) {
while (subclause != condition) {
subclause->pause = 1;
subclause = subclause->next;
}
condition->pause = 1;
}
else {
condition->pause = 0;
}
default:
*in_pause = condition->pause = 0;
break;
if (!rc_condition_is_combining(condition))
subclause = condition->next;
condition = condition->next;
}
}
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, int is_value) {
rc_condset_t* self;
rc_condition_t** next;
int in_pause;
int in_add_address;
unsigned measured_target = 0;
@@ -85,8 +81,20 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
}
else if (is_value) {
measured_target = (unsigned)-1;
if ((*next)->oper != RC_OPERATOR_NONE)
(*next)->required_hits = measured_target;
switch ((*next)->oper)
{
case RC_OPERATOR_AND:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_NONE:
/* measuring value. leave required_hits at 0 */
break;
default:
/* comparison operator, measuring hits. set required_hits to MAX_INT */
(*next)->required_hits = measured_target;
break;
}
}
else if ((*next)->required_hits != 0) {
measured_target = (*next)->required_hits;
@@ -94,6 +102,9 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
else if ((*next)->operand2.type == RC_OPERAND_CONST) {
measured_target = (*next)->operand2.value.num;
}
else if ((*next)->operand2.type == RC_OPERAND_FP) {
measured_target = (unsigned)(*next)->operand2.value.dbl;
}
else {
parse->offset = RC_INVALID_MEASURED_TARGET;
return 0;
@@ -132,10 +143,8 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
*next = 0;
if (parse->buffer != 0) {
in_pause = 0;
rc_update_condition_pause(self->conditions, &in_pause);
}
if (parse->buffer != 0)
rc_update_condition_pause(self->conditions);
return self;
}
@@ -146,7 +155,10 @@ static void rc_condset_update_indirect_memrefs(rc_condition_t* condition, int pr
continue;
if (condition->type == RC_CONDITION_ADD_ADDRESS) {
eval_state->add_address = rc_evaluate_condition_value(condition, eval_state);
rc_typed_value_t value;
rc_evaluate_condition_value(&value, condition, eval_state);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
eval_state->add_address = value.value.u32;
continue;
}
@@ -163,20 +175,25 @@ static void rc_condset_update_indirect_memrefs(rc_condition_t* condition, int pr
}
}
static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc_eval_state_t* eval_state) {
rc_condition_t* condition;
int set_valid, cond_valid, and_next, or_next, reset_next;
unsigned measured_value = 0;
unsigned total_hits = 0;
int can_measure = 1, measured_from_hits = 0;
rc_typed_value_t value;
int set_valid, cond_valid, and_next, or_next, reset_next, measured_from_hits, can_measure;
rc_typed_value_t measured_value;
unsigned total_hits;
measured_value.type = RC_VALUE_TYPE_NONE;
measured_from_hits = 0;
can_measure = 1;
total_hits = 0;
eval_state->primed = 1;
set_valid = 1;
and_next = 1;
or_next = 0;
reset_next = 0;
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
eval_state->add_value.type = RC_VALUE_TYPE_NONE;
eval_state->add_hits = eval_state->add_address = 0;
for (condition = self->conditions; condition != 0; condition = condition->next) {
if (condition->pause != processing_pause)
@@ -185,23 +202,30 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
/* STEP 1: process modifier conditions */
switch (condition->type) {
case RC_CONDITION_ADD_SOURCE:
eval_state->add_value += rc_evaluate_condition_value(condition, eval_state);
rc_evaluate_condition_value(&value, condition, eval_state);
rc_typed_value_add(&eval_state->add_value, &value);
eval_state->add_address = 0;
continue;
case RC_CONDITION_SUB_SOURCE:
eval_state->add_value -= rc_evaluate_condition_value(condition, eval_state);
rc_evaluate_condition_value(&value, condition, eval_state);
rc_typed_value_convert(&value, RC_VALUE_TYPE_SIGNED);
value.value.i32 = -value.value.i32;
rc_typed_value_add(&eval_state->add_value, &value);
eval_state->add_address = 0;
continue;
case RC_CONDITION_ADD_ADDRESS:
eval_state->add_address = rc_evaluate_condition_value(condition, eval_state);
rc_evaluate_condition_value(&value, condition, eval_state);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
eval_state->add_address = value.value.u32;
continue;
case RC_CONDITION_MEASURED:
if (condition->required_hits == 0) {
if (condition->required_hits == 0 && can_measure) {
/* Measured condition without a hit target measures the value of the left operand */
measured_value = rc_evaluate_condition_value(condition, eval_state) + eval_state->add_value;
rc_evaluate_condition_value(&measured_value, condition, eval_state);
rc_typed_value_add(&measured_value, &eval_state->add_value);
}
break;
@@ -211,7 +235,7 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
/* STEP 2: evaluate the current condition */
condition->is_true = (char)rc_test_condition(condition, eval_state);
eval_state->add_value = 0;
eval_state->add_value.type = RC_VALUE_TYPE_NONE;
eval_state->add_address = 0;
/* apply logic flags and reset them for the next condition */
@@ -345,13 +369,19 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
if (condition->required_hits != 0) {
/* if there's a hit target, capture the current hits for recording Measured value later */
measured_from_hits = 1;
measured_value = total_hits;
if (can_measure) {
measured_value.value.u32 = total_hits;
measured_value.type = RC_VALUE_TYPE_UNSIGNED;
}
}
break;
case RC_CONDITION_MEASURED_IF:
if (!cond_valid)
if (!cond_valid) {
measured_value.value.u32 = 0;
measured_value.type = RC_VALUE_TYPE_UNSIGNED;
can_measure = 0;
}
break;
case RC_CONDITION_TRIGGER:
@@ -368,10 +398,13 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
set_valid &= cond_valid;
}
/* if not suppressed, update the measured value */
if (measured_value > eval_state->measured_value && can_measure) {
eval_state->measured_value = measured_value;
eval_state->measured_from_hits = (char)measured_from_hits;
if (measured_value.type != RC_VALUE_TYPE_NONE) {
/* if no previous Measured value was captured, or the new one is greater, keep the new one */
if (eval_state->measured_value.type == RC_VALUE_TYPE_NONE ||
rc_typed_value_compare(&measured_value, &eval_state->measured_value, RC_OPERATOR_GT)) {
memcpy(&eval_state->measured_value, &measured_value, sizeof(measured_value));
eval_state->measured_from_hits = (char)measured_from_hits;
}
}
return set_valid;
+72
View File
@@ -21,6 +21,9 @@ const char* rc_console_name(int console_id)
case RC_CONSOLE_ARCADE:
return "Arcade";
case RC_CONSOLE_ARDUBOY:
return "Arduboy";
case RC_CONSOLE_ATARI_2600:
return "Atari 2600";
@@ -96,6 +99,9 @@ const char* rc_console_name(int console_id)
case RC_CONSOLE_MEGA_DRIVE:
return "Sega Genesis";
case RC_CONSOLE_MEGADUCK:
return "Mega Duck";
case RC_CONSOLE_MS_DOS:
return "MS-DOS";
@@ -126,6 +132,9 @@ const char* rc_console_name(int console_id)
case RC_CONSOLE_ORIC:
return "Oric";
case RC_CONSOLE_PC6000:
return "PC-6000";
case RC_CONSOLE_PC8800:
return "PC-8000/8800";
@@ -155,6 +164,9 @@ const char* rc_console_name(int console_id)
case RC_CONSOLE_SEGA_CD:
return "Sega CD";
case RC_CONSOLE_PICO:
return "Sega Pico";
case RC_CONSOLE_SATURN:
return "Sega Saturn";
@@ -204,6 +216,9 @@ const char* rc_console_name(int console_id)
case RC_CONSOLE_XBOX:
return "XBOX";
case RC_CONSOLE_ZEEBO:
return "Zeebo";
case RC_CONSOLE_ZX81:
return "ZX-81";
@@ -227,6 +242,20 @@ static const rc_memory_region_t _rc_memory_regions_3do[] = {
};
static const rc_memory_regions_t rc_memory_regions_3do = { _rc_memory_regions_3do, 1 };
/* ===== Amstrad CPC ===== */
/* http://www.cpcalive.com/docs/amstrad_cpc_6128_memory_map.html */
/* https://www.cpcwiki.eu/index.php/File:AWMG_page151.jpg */
/* The original CPC only had 64KB of memory, but the newer model has 128KB (expandable to 576KB) */
/* https://www.grimware.org/doku.php/documentations/devices/gatearraydo=export_xhtml#mmr */
static const rc_memory_region_t _rc_memory_regions_amstrad_pc[] = {
{ 0x000000U, 0x00003FU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Firmware" },
{ 0x000040U, 0x00B0FFU, 0x000040U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x00B100U, 0x00BFFFU, 0x00B100U, RC_MEMORY_TYPE_SYSTEM_RAM, "Stack and Firmware Data" },
{ 0x00C000U, 0x00FFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Screen Memory" },
{ 0x010000U, 0x08FFFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Extended RAM" },
};
static const rc_memory_regions_t rc_memory_regions_amstrad_pc = { _rc_memory_regions_amstrad_pc, 5 };
/* ===== Apple II ===== */
static const rc_memory_region_t _rc_memory_regions_appleii[] = {
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" },
@@ -234,6 +263,21 @@ static const rc_memory_region_t _rc_memory_regions_appleii[] = {
};
static const rc_memory_regions_t rc_memory_regions_appleii = { _rc_memory_regions_appleii, 2 };
/* ===== Arduboy ===== */
/* https://scienceprog.com/avr-microcontroller-memory-map/ (Atmega32) */
static const rc_memory_region_t _rc_memory_regions_arduboy[] = {
{ 0x000000U, 0x0000FFU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Registers" },
/* https://www.dailydot.com/debug/arduboy-kickstarter/ 2.5KB of RAM */
/* https://github.com/buserror/simavr/blob/1d227277b3d0039f9faef9ea62880ca3051b14f8/simavr/cores/avr/iom32u4.h#L1444-L1445 */
{ 0x000100U, 0x000AFFU, 0x00000100U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* 1KB of EEPROM https://github.com/libretro/arduous/blob/93e1a6289b42ef48de1fcfb96443981725955ad0/src/arduous/arduous.cpp#L453-L455
* https://github.com/buserror/simavr/blob/1d227277b3d0039f9faef9ea62880ca3051b14f8/simavr/cores/avr/iom32u4.h#L1450 */
/* EEPROM has it's own addressing scheme starting at $0000. I've chosen to virtualize the address
* at $80000000 to avoid a conflict */
{ 0x000B00U, 0x000EFFU, 0x80000000U, RC_MEMORY_TYPE_SAVE_RAM, "EEPROM" }
};
static const rc_memory_regions_t rc_memory_regions_arduboy = { _rc_memory_regions_arduboy, 3 };
/* ===== Atari 2600 ===== */
static const rc_memory_region_t _rc_memory_regions_atari2600[] = {
{ 0x000000U, 0x00007FU, 0x000080U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
@@ -280,6 +324,13 @@ static const rc_memory_region_t _rc_memory_regions_colecovision[] = {
};
static const rc_memory_regions_t rc_memory_regions_colecovision = { _rc_memory_regions_colecovision, 1 };
/* ===== Dreamcast ===== */
/* http://archiv.sega-dc.de/munkeechuff/hardware/Memory.html */
static const rc_memory_region_t _rc_memory_regions_dreamcast[] = {
{ 0x00000000U, 0x00FFFFFFU, 0x0C000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
};
static const rc_memory_regions_t rc_memory_regions_dreamcast = { _rc_memory_regions_dreamcast, 1 };
/* ===== GameBoy / GameBoy Color ===== */
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
@@ -506,6 +557,14 @@ static const rc_memory_region_t _rc_memory_regions_playstation2[] = {
};
static const rc_memory_regions_t rc_memory_regions_playstation2 = { _rc_memory_regions_playstation2, 2 };
/* ===== PlayStation Portable ===== */
/* https://github.com/uofw/upspd/wiki/Memory-map */
static const rc_memory_region_t _rc_memory_regions_psp[] = {
{ 0x00000000U, 0x007FFFFFU, 0x08000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
{ 0x00800000U, 0x01FFFFFFU, 0x08800000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
};
static const rc_memory_regions_t rc_memory_regions_psp = { _rc_memory_regions_psp, 2 };
/* ===== Pokemon Mini ===== */
/* https://www.pokemon-mini.net/documentation/memory-map/ */
static const rc_memory_region_t _rc_memory_regions_pokemini[] = {
@@ -638,9 +697,15 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
case RC_CONSOLE_3DO:
return &rc_memory_regions_3do;
case RC_CONSOLE_AMSTRAD_PC:
return &rc_memory_regions_amstrad_pc;
case RC_CONSOLE_APPLE_II:
return &rc_memory_regions_appleii;
case RC_CONSOLE_ARDUBOY:
return &rc_memory_regions_arduboy;
case RC_CONSOLE_ATARI_2600:
return &rc_memory_regions_atari2600;
@@ -656,6 +721,10 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
case RC_CONSOLE_COLECOVISION:
return &rc_memory_regions_colecovision;
case RC_CONSOLE_DREAMCAST:
return &rc_memory_regions_dreamcast;
case RC_CONSOLE_MEGADUCK:
case RC_CONSOLE_GAMEBOY:
return &rc_memory_regions_gameboy;
@@ -716,6 +785,9 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
case RC_CONSOLE_PLAYSTATION_2:
return &rc_memory_regions_playstation2;
case RC_CONSOLE_PSP:
return &rc_memory_regions_psp;
case RC_CONSOLE_POKEMON_MINI:
return &rc_memory_regions_pokemini;
+65 -14
View File
@@ -11,6 +11,9 @@ int rc_parse_format(const char* format_str) {
if (!strcmp(format_str, "RAMES")) {
return RC_FORMAT_FRAMES;
}
if (!strncmp(format_str, "LOAT", 4) && format_str[4] >= '1' && format_str[4] <= '6' && format_str[5] == '\0') {
return RC_FORMAT_FLOAT1 + (format_str[4] - '1');
}
break;
@@ -18,7 +21,7 @@ int rc_parse_format(const char* format_str) {
if (!strcmp(format_str, "IME")) {
return RC_FORMAT_FRAMES;
}
else if (!strcmp(format_str, "IMESECS")) {
if (!strcmp(format_str, "IMESECS")) {
return RC_FORMAT_SECONDS;
}
@@ -116,40 +119,88 @@ static int rc_format_value_centiseconds(char* buffer, int size, unsigned centise
return chars;
}
int rc_format_value(char* buffer, int size, int value, int format) {
int rc_format_typed_value(char* buffer, int size, const rc_typed_value_t* value, int format) {
int chars;
rc_typed_value_t converted_value;
memcpy(&converted_value, value, sizeof(converted_value));
switch (format) {
case RC_FORMAT_FRAMES:
/* 60 frames per second = 100 centiseconds / 60 frames; multiply frames by 100 / 60 */
chars = rc_format_value_centiseconds(buffer, size, value * 10 / 6);
default:
case RC_FORMAT_VALUE:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = snprintf(buffer, size, "%d", converted_value.value.i32);
break;
case RC_FORMAT_SECONDS:
chars = rc_format_value_seconds(buffer, size, value);
case RC_FORMAT_FRAMES:
/* 60 frames per second = 100 centiseconds / 60 frames; multiply frames by 100 / 60 */
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = rc_format_value_centiseconds(buffer, size, converted_value.value.u32 * 10 / 6);
break;
case RC_FORMAT_CENTISECS:
chars = rc_format_value_centiseconds(buffer, size, value);
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = rc_format_value_centiseconds(buffer, size, converted_value.value.u32);
break;
case RC_FORMAT_SECONDS:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = rc_format_value_seconds(buffer, size, converted_value.value.u32);
break;
case RC_FORMAT_SECONDS_AS_MINUTES:
chars = rc_format_value_minutes(buffer, size, value / 60);
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = rc_format_value_minutes(buffer, size, converted_value.value.u32 / 60);
break;
case RC_FORMAT_MINUTES:
chars = rc_format_value_minutes(buffer, size, value);
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_UNSIGNED);
chars = rc_format_value_minutes(buffer, size, converted_value.value.u32);
break;
case RC_FORMAT_SCORE:
chars = snprintf(buffer, size, "%06d", value);
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_SIGNED);
chars = snprintf(buffer, size, "%06d", converted_value.value.i32);
break;
default:
case RC_FORMAT_VALUE:
chars = snprintf(buffer, size, "%d", value);
case RC_FORMAT_FLOAT1:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.1f", converted_value.value.f32);
break;
case RC_FORMAT_FLOAT2:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.2f", converted_value.value.f32);
break;
case RC_FORMAT_FLOAT3:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.3f", converted_value.value.f32);
break;
case RC_FORMAT_FLOAT4:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.4f", converted_value.value.f32);
break;
case RC_FORMAT_FLOAT5:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.5f", converted_value.value.f32);
break;
case RC_FORMAT_FLOAT6:
rc_typed_value_convert(&converted_value, RC_VALUE_TYPE_FLOAT);
chars = snprintf(buffer, size, "%.6f", converted_value.value.f32);
break;
}
return chars;
}
int rc_format_value(char* buffer, int size, int value, int format) {
rc_typed_value_t typed_value;
typed_value.value.i32 = value;
typed_value.type = RC_VALUE_TYPE_SIGNED;
return rc_format_typed_value(buffer, size, &typed_value, format);
}
+38 -16
View File
@@ -25,10 +25,12 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
return;
}
found |= RC_LBOARD_START;
memaddr += 4;
rc_parse_trigger_internal(&self->start, &memaddr, parse);
self->start.memrefs = 0;
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_START;
rc_parse_trigger_internal(&self->start, &memaddr, parse);
self->start.memrefs = 0;
}
}
else if ((memaddr[0] == 'c' || memaddr[0] == 'C') &&
(memaddr[1] == 'a' || memaddr[1] == 'A') &&
@@ -38,10 +40,12 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
return;
}
found |= RC_LBOARD_CANCEL;
memaddr += 4;
rc_parse_trigger_internal(&self->cancel, &memaddr, parse);
self->cancel.memrefs = 0;
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_CANCEL;
rc_parse_trigger_internal(&self->cancel, &memaddr, parse);
self->cancel.memrefs = 0;
}
}
else if ((memaddr[0] == 's' || memaddr[0] == 'S') &&
(memaddr[1] == 'u' || memaddr[1] == 'U') &&
@@ -51,10 +55,12 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
return;
}
found |= RC_LBOARD_SUBMIT;
memaddr += 4;
rc_parse_trigger_internal(&self->submit, &memaddr, parse);
self->submit.memrefs = 0;
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_SUBMIT;
rc_parse_trigger_internal(&self->submit, &memaddr, parse);
self->submit.memrefs = 0;
}
}
else if ((memaddr[0] == 'v' || memaddr[0] == 'V') &&
(memaddr[1] == 'a' || memaddr[1] == 'A') &&
@@ -64,10 +70,12 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
return;
}
found |= RC_LBOARD_VALUE;
memaddr += 4;
rc_parse_value_internal(&self->value, &memaddr, parse);
self->value.memrefs = 0;
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_VALUE;
rc_parse_value_internal(&self->value, &memaddr, parse);
self->value.memrefs = 0;
}
}
else if ((memaddr[0] == 'p' || memaddr[0] == 'P') &&
(memaddr[1] == 'r' || memaddr[1] == 'R') &&
@@ -77,12 +85,14 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
return;
}
found |= RC_LBOARD_PROGRESS;
memaddr += 4;
if (*memaddr && *memaddr != ':') {
found |= RC_LBOARD_PROGRESS;
self->progress = RC_ALLOC(rc_value_t, parse);
rc_parse_value_internal(self->progress, &memaddr, parse);
self->progress->memrefs = 0;
self->progress = RC_ALLOC(rc_value_t, parse);
rc_parse_value_internal(self->progress, &memaddr, parse);
self->progress->memrefs = 0;
}
}
/* encountered an error parsing one of the parts */
@@ -239,6 +249,18 @@ int rc_evaluate_lboard(rc_lboard_t* self, int* value, rc_peek_t peek, void* peek
return self->state;
}
int rc_lboard_state_active(int state) {
switch (state)
{
case RC_LBOARD_STATE_DISABLED:
case RC_LBOARD_STATE_INACTIVE:
return 0;
default:
return 1;
}
}
void rc_reset_lboard(rc_lboard_t* self) {
self->state = RC_LBOARD_STATE_WAITING;
+218 -86
View File
@@ -2,6 +2,7 @@
#include <stdlib.h> /* malloc/realloc */
#include <string.h> /* memcpy */
#include <math.h> /* INFINITY/NAN */
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
@@ -45,50 +46,62 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
char* end;
unsigned long value;
if (*aux++ != '0')
return RC_INVALID_MEMORY_OPERAND;
if (*aux != 'x' && *aux != 'X')
return RC_INVALID_MEMORY_OPERAND;
aux++;
switch (*aux++) {
/* ordered by estimated frequency in case compiler doesn't build a jump table */
case 'h': case 'H': *size = RC_MEMSIZE_8_BITS; break;
case ' ': *size = RC_MEMSIZE_16_BITS; break;
case 'x': case 'X': *size = RC_MEMSIZE_32_BITS; break;
case 'm': case 'M': *size = RC_MEMSIZE_BIT_0; break;
case 'n': case 'N': *size = RC_MEMSIZE_BIT_1; break;
case 'o': case 'O': *size = RC_MEMSIZE_BIT_2; break;
case 'p': case 'P': *size = RC_MEMSIZE_BIT_3; break;
case 'q': case 'Q': *size = RC_MEMSIZE_BIT_4; break;
case 'r': case 'R': *size = RC_MEMSIZE_BIT_5; break;
case 's': case 'S': *size = RC_MEMSIZE_BIT_6; break;
case 't': case 'T': *size = RC_MEMSIZE_BIT_7; break;
case 'l': case 'L': *size = RC_MEMSIZE_LOW; break;
case 'u': case 'U': *size = RC_MEMSIZE_HIGH; break;
case 'k': case 'K': *size = RC_MEMSIZE_BITCOUNT; break;
case 'w': case 'W': *size = RC_MEMSIZE_24_BITS; break;
case 'g': case 'G': *size = RC_MEMSIZE_32_BITS_BE; break;
case 'i': case 'I': *size = RC_MEMSIZE_16_BITS_BE; break;
case 'j': case 'J': *size = RC_MEMSIZE_24_BITS_BE; break;
/* case 'v': case 'V': */
/* case 'y': case 'Y': 64 bit? */
/* case 'z': case 'Z': 128 bit? */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
/* legacy support - addresses without a size prefix are assumed to be 16-bit */
aux--;
*size = RC_MEMSIZE_16_BITS;
break;
default:
if (aux[0] == '0') {
if (aux[1] != 'x' && aux[1] != 'X')
return RC_INVALID_MEMORY_OPERAND;
aux += 2;
switch (*aux++) {
/* ordered by estimated frequency in case compiler doesn't build a jump table */
case 'h': case 'H': *size = RC_MEMSIZE_8_BITS; break;
case ' ': *size = RC_MEMSIZE_16_BITS; break;
case 'x': case 'X': *size = RC_MEMSIZE_32_BITS; break;
case 'm': case 'M': *size = RC_MEMSIZE_BIT_0; break;
case 'n': case 'N': *size = RC_MEMSIZE_BIT_1; break;
case 'o': case 'O': *size = RC_MEMSIZE_BIT_2; break;
case 'p': case 'P': *size = RC_MEMSIZE_BIT_3; break;
case 'q': case 'Q': *size = RC_MEMSIZE_BIT_4; break;
case 'r': case 'R': *size = RC_MEMSIZE_BIT_5; break;
case 's': case 'S': *size = RC_MEMSIZE_BIT_6; break;
case 't': case 'T': *size = RC_MEMSIZE_BIT_7; break;
case 'l': case 'L': *size = RC_MEMSIZE_LOW; break;
case 'u': case 'U': *size = RC_MEMSIZE_HIGH; break;
case 'k': case 'K': *size = RC_MEMSIZE_BITCOUNT; break;
case 'w': case 'W': *size = RC_MEMSIZE_24_BITS; break;
case 'g': case 'G': *size = RC_MEMSIZE_32_BITS_BE; break;
case 'i': case 'I': *size = RC_MEMSIZE_16_BITS_BE; break;
case 'j': case 'J': *size = RC_MEMSIZE_24_BITS_BE; break;
/* case 'v': case 'V': */
/* case 'y': case 'Y': 64 bit? */
/* case 'z': case 'Z': 128 bit? */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
/* legacy support - addresses without a size prefix are assumed to be 16-bit */
aux--;
*size = RC_MEMSIZE_16_BITS;
break;
default:
return RC_INVALID_MEMORY_OPERAND;
}
}
else if (aux[0] == 'f' || aux[0] == 'F') {
++aux;
switch (*aux++) {
case 'f': case 'F': *size = RC_MEMSIZE_FLOAT; break;
case 'm': case 'M': *size = RC_MEMSIZE_MBF32; break;
default:
return RC_INVALID_FP_OPERAND;
}
}
else {
return RC_INVALID_MEMORY_OPERAND;
}
value = strtoul(aux, &end, 16);
@@ -104,94 +117,212 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
return RC_OK;
}
static float rc_build_float(unsigned mantissa_bits, int exponent, int sign) {
/* 32-bit float has a 23-bit mantissa and 8-bit exponent */
const unsigned mantissa = mantissa_bits | 0x800000;
double dbl = ((double)mantissa) / ((double)0x800000);
if (exponent > 127) {
/* exponent above 127 is a special number */
if (mantissa_bits == 0) {
/* infinity */
#ifdef INFINITY /* INFINITY and NAN #defines require C99 */
dbl = INFINITY;
#else
dbl = -log(0.0);
#endif
}
else {
/* NaN */
#ifdef NAN
dbl = NAN;
#else
dbl = -sqrt(-1);
#endif
}
}
else if (exponent > 0) {
/* exponent from 1 to 127 is a number greater than 1 */
while (exponent > 30) {
dbl *= (double)(1 << 30);
exponent -= 30;
}
dbl *= (double)((long long)1 << exponent);
}
else if (exponent < 0) {
/* exponent from -1 to -127 is a number less than 1 */
exponent = -exponent;
while (exponent > 30) {
dbl /= (double)(1 << 30);
exponent -= 30;
}
dbl /= (double)((long long)1 << exponent);
}
else {
/* exponent of 0 requires no adjustment */
}
return (sign) ? (float)-dbl : (float)dbl;
}
static void rc_transform_memref_float(rc_typed_value_t* value) {
/* decodes an IEEE 754 float */
const unsigned mantissa = (value->value.u32 & 0x7FFFFF);
const int exponent = (int)((value->value.u32 >> 23) & 0xFF) - 127;
const int sign = (value->value.u32 & 0x80000000);
if (mantissa == 0 && exponent == -127)
value->value.f32 = (sign) ? -0.0f : 0.0f;
else
value->value.f32 = rc_build_float(mantissa, exponent, sign);
value->type = RC_VALUE_TYPE_FLOAT;
}
static void rc_transform_memref_mbf32(rc_typed_value_t* value) {
/* decodes a Microsoft Binary Format float */
/* NOTE: 32-bit MBF is stored in memory as big endian (at least for Apple II) */
const unsigned mantissa = ((value->value.u32 & 0xFF000000) >> 24) |
((value->value.u32 & 0x00FF0000) >> 8) |
((value->value.u32 & 0x00007F00) << 8);
const int exponent = (int)(value->value.u32 & 0xFF) - 129;
const int sign = (value->value.u32 & 0x00008000);
if (mantissa == 0 && exponent == -129)
value->value.f32 = (sign) ? -0.0f : 0.0f;
else
value->value.f32 = rc_build_float(mantissa, exponent, sign);
value->type = RC_VALUE_TYPE_FLOAT;
}
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
unsigned rc_transform_memref_value(unsigned value, char size) {
void rc_transform_memref_value(rc_typed_value_t* value, char size) {
/* ASSERT: value->type == RC_VALUE_TYPE_UNSIGNED */
switch (size)
{
case RC_MEMSIZE_8_BITS:
value = (value & 0x000000ff);
value->value.u32 = (value->value.u32 & 0x000000ff);
break;
case RC_MEMSIZE_16_BITS:
value = (value & 0x0000ffff);
value->value.u32 = (value->value.u32 & 0x0000ffff);
break;
case RC_MEMSIZE_24_BITS:
value = (value & 0x00ffffff);
value->value.u32 = (value->value.u32 & 0x00ffffff);
break;
case RC_MEMSIZE_32_BITS:
break;
case RC_MEMSIZE_BIT_0:
value = (value >> 0) & 1;
value->value.u32 = (value->value.u32 >> 0) & 1;
break;
case RC_MEMSIZE_BIT_1:
value = (value >> 1) & 1;
value->value.u32 = (value->value.u32 >> 1) & 1;
break;
case RC_MEMSIZE_BIT_2:
value = (value >> 2) & 1;
value->value.u32 = (value->value.u32 >> 2) & 1;
break;
case RC_MEMSIZE_BIT_3:
value = (value >> 3) & 1;
value->value.u32 = (value->value.u32 >> 3) & 1;
break;
case RC_MEMSIZE_BIT_4:
value = (value >> 4) & 1;
value->value.u32 = (value->value.u32 >> 4) & 1;
break;
case RC_MEMSIZE_BIT_5:
value = (value >> 5) & 1;
value->value.u32 = (value->value.u32 >> 5) & 1;
break;
case RC_MEMSIZE_BIT_6:
value = (value >> 6) & 1;
value->value.u32 = (value->value.u32 >> 6) & 1;
break;
case RC_MEMSIZE_BIT_7:
value = (value >> 7) & 1;
value->value.u32 = (value->value.u32 >> 7) & 1;
break;
case RC_MEMSIZE_LOW:
value = value & 0x0f;
value->value.u32 = value->value.u32 & 0x0f;
break;
case RC_MEMSIZE_HIGH:
value = (value >> 4) & 0x0f;
value->value.u32 = (value->value.u32 >> 4) & 0x0f;
break;
case RC_MEMSIZE_BITCOUNT:
value = rc_bits_set[(value & 0x0F)]
+ rc_bits_set[((value >> 4) & 0x0F)];
value->value.u32 = rc_bits_set[(value->value.u32 & 0x0F)]
+ rc_bits_set[((value->value.u32 >> 4) & 0x0F)];
break;
case RC_MEMSIZE_16_BITS_BE:
value = ((value & 0xFF00) >> 8) |
((value & 0x00FF) << 8);
value->value.u32 = ((value->value.u32 & 0xFF00) >> 8) |
((value->value.u32 & 0x00FF) << 8);
break;
case RC_MEMSIZE_24_BITS_BE:
value = ((value & 0xFF0000) >> 16) |
(value & 0x00FF00) |
((value & 0x0000FF) << 16);
value->value.u32 = ((value->value.u32 & 0xFF0000) >> 16) |
(value->value.u32 & 0x00FF00) |
((value->value.u32 & 0x0000FF) << 16);
break;
case RC_MEMSIZE_32_BITS_BE:
value = ((value & 0xFF000000) >> 24) |
((value & 0x00FF0000) >> 8) |
((value & 0x0000FF00) << 8) |
((value & 0x000000FF) << 24);
value->value.u32 = ((value->value.u32 & 0xFF000000) >> 24) |
((value->value.u32 & 0x00FF0000) >> 8) |
((value->value.u32 & 0x0000FF00) << 8) |
((value->value.u32 & 0x000000FF) << 24);
break;
case RC_MEMSIZE_FLOAT:
rc_transform_memref_float(value);
break;
case RC_MEMSIZE_MBF32:
rc_transform_memref_mbf32(value);
break;
default:
break;
}
}
return value;
static const unsigned rc_memref_masks[] = {
0x000000ff, /* RC_MEMSIZE_8_BITS */
0x0000ffff, /* RC_MEMSIZE_16_BITS */
0x00ffffff, /* RC_MEMSIZE_24_BITS */
0xffffffff, /* RC_MEMSIZE_32_BITS */
0x0000000f, /* RC_MEMSIZE_LOW */
0x000000f0, /* RC_MEMSIZE_HIGH */
0x00000001, /* RC_MEMSIZE_BIT_0 */
0x00000002, /* RC_MEMSIZE_BIT_1 */
0x00000004, /* RC_MEMSIZE_BIT_2 */
0x00000008, /* RC_MEMSIZE_BIT_3 */
0x00000010, /* RC_MEMSIZE_BIT_4 */
0x00000020, /* RC_MEMSIZE_BIT_5 */
0x00000040, /* RC_MEMSIZE_BIT_6 */
0x00000080, /* RC_MEMSIZE_BIT_7 */
0x000000ff, /* RC_MEMSIZE_BITCOUNT */
0x0000ffff, /* RC_MEMSIZE_16_BITS_BE */
0x00ffffff, /* RC_MEMSIZE_24_BITS_BE */
0xffffffff, /* RC_MEMSIZE_32_BITS_BE */
0xffffffff, /* RC_MEMSIZE_FLOAT */
0xffffffff, /* RC_MEMSIZE_MBF32 */
0xffffffff /* RC_MEMSIZE_VARIABLE */
};
unsigned rc_memref_mask(char size) {
const size_t index = (size_t)size;
if (index >= sizeof(rc_memref_masks) / sizeof(rc_memref_masks[0]))
return 0xffffffff;
return rc_memref_masks[index];
}
/* all sizes less than 8-bits (1 byte) are mapped to 8-bits. 24-bit is mapped to 32-bit
@@ -216,6 +347,8 @@ static const char rc_memref_shared_sizes[] = {
RC_MEMSIZE_16_BITS, /* RC_MEMSIZE_16_BITS_BE */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_24_BITS_BE */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_32_BITS_BE */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_FLOAT */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_MBF32 */
RC_MEMSIZE_32_BITS /* RC_MEMSIZE_VARIABLE */
};
@@ -228,35 +361,34 @@ char rc_memref_shared_size(char size) {
}
static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
unsigned value;
char shared_size;
if (!peek)
return 0;
shared_size = rc_memref_shared_size(size);
switch (shared_size)
switch (size)
{
case RC_MEMSIZE_8_BITS:
value = peek(address, 1, ud);
break;
return peek(address, 1, ud);
case RC_MEMSIZE_16_BITS:
value = peek(address, 2, ud);
break;
return peek(address, 2, ud);
case RC_MEMSIZE_32_BITS:
value = peek(address, 4, ud);
break;
return peek(address, 4, ud);
default:
return 0;
{
unsigned value;
const size_t index = (size_t)size;
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
return 0;
/* fetch the larger value and mask off the bits associated to the specified size
* for correct deduction of prior value. non-prior memrefs should already be using
* shared size memrefs to minimize the total number of memory reads required. */
value = rc_peek_value(address, rc_memref_shared_sizes[index], peek, ud);
return value & rc_memref_masks[index];
}
}
if (shared_size != size)
value = rc_transform_memref_value(value, size);
return value;
}
void rc_update_memref_value(rc_memref_value_t* memref, unsigned new_value) {
+120 -74
View File
@@ -103,6 +103,16 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
return ret;
size = rc_memref_shared_size(self->size);
if (size != self->size && self->type == RC_OPERAND_PRIOR) {
/* if the shared size differs from the requested size and it's a prior operation, we
* have to check to make sure both sizes use the same mask, or the prior value may be
* updated when bits outside the mask are modified, which would make it look like the
* current value once the mask is applied. if the mask differs, create a new
* non-shared record for tracking the prior data. */
if (rc_memref_mask(size) != rc_memref_mask(self->size))
size = self->size;
}
self->value.memref = rc_alloc_memref(parse, address, size, (char)is_indirect);
if (parse->offset < 0)
return parse->offset;
@@ -142,6 +152,14 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect,
break;
case 'f': case 'F': /* floating point constant */
if (isalpha((unsigned char)aux[1])) {
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
if (ret < 0)
return ret;
break;
}
allow_decimal = 1;
/* fall through */
case 'v': case 'V': /* signed integer constant */
@@ -169,13 +187,16 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect,
return RC_INVALID_FP_OPERAND;
do {
fraction *= 10;
fraction += (*aux - '0');
shift *= 10;
/* only keep as many digits as will fit in a 32-bit value to prevent overflow.
* float only has around 7 digits of precision anyway. */
if (shift < 1000000000) {
fraction *= 10;
fraction += (*aux - '0');
shift *= 10;
}
++aux;
} while (*aux >= '0' && *aux <= '9');
/* if fractional part is 0, convert to an integer constant */
if (fraction != 0) {
/* non-zero fractional part, convert to double and merge in integer portion */
const double dbl_fraction = ((double)fraction) / ((double)shift);
@@ -183,28 +204,34 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect,
self->value.dbl = ((double)(-((long)value))) - dbl_fraction;
else
self->value.dbl = (double)value + dbl_fraction;
self->type = RC_OPERAND_FP;
break;
}
} else {
else {
/* fractional part is 0, just convert the integer portion */
if (negative)
self->value.dbl = (double)(-((long)value));
else
self->value.dbl = (double)value;
}
self->type = RC_OPERAND_FP;
}
else {
/* not a floating point value, make sure something was read and advance the read pointer */
if (end == aux)
return allow_decimal ? RC_INVALID_FP_OPERAND : RC_INVALID_CONST_OPERAND;
aux = end;
if (value > 0x7fffffffU)
value = 0x7fffffffU;
self->type = RC_OPERAND_CONST;
if (negative)
self->value.num = (unsigned)(-((long)value));
else
self->value.num = (unsigned)value;
}
if (value > 0x7fffffffU)
value = 0x7fffffffU;
self->type = RC_OPERAND_CONST;
if (negative)
self->value.num = (unsigned)(-((long)value));
else
self->value.num = (unsigned)value;
break;
case '0':
@@ -269,7 +296,18 @@ static int rc_luapeek(lua_State* L) {
#endif /* RC_DISABLE_LUA */
int rc_operand_is_memref(rc_operand_t* self) {
int rc_operand_is_float_memref(const rc_operand_t* self) {
switch (self->size) {
case RC_MEMSIZE_FLOAT:
case RC_MEMSIZE_MBF32:
return 1;
default:
return 0;
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
switch (self->type) {
case RC_OPERAND_CONST:
case RC_OPERAND_FP:
@@ -281,60 +319,7 @@ int rc_operand_is_memref(rc_operand_t* self) {
}
}
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
#ifndef RC_DISABLE_LUA
rc_luapeek_t luapeek;
#endif /* RC_DISABLE_LUA */
unsigned value;
/* step 1: read memory */
switch (self->type) {
case RC_OPERAND_CONST:
return self->value.num;
case RC_OPERAND_FP:
/* This is handled by rc_evaluate_condition_value. */
return 0;
case RC_OPERAND_LUA:
value = 0;
#ifndef RC_DISABLE_LUA
if (eval_state->L != 0) {
lua_rawgeti(eval_state->L, LUA_REGISTRYINDEX, self->value.luafunc);
lua_pushcfunction(eval_state->L, rc_luapeek);
luapeek.peek = eval_state->peek;
luapeek.ud = eval_state->peek_userdata;
lua_pushlightuserdata(eval_state->L, &luapeek);
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
if (lua_isboolean(eval_state->L, -1)) {
value = lua_toboolean(eval_state->L, -1);
}
else {
value = (unsigned)lua_tonumber(eval_state->L, -1);
}
}
lua_pop(eval_state->L, 1);
}
#endif /* RC_DISABLE_LUA */
break;
default:
value = rc_get_memref_value(self->value.memref, self->type, eval_state);
break;
}
/* step 2: mask off appropriate bits */
value = rc_transform_memref_value(value, self->size);
/* step 3: apply logic */
unsigned rc_transform_operand_value(unsigned value, const rc_operand_t* self) {
switch (self->type)
{
case RC_OPERAND_BCD:
@@ -421,3 +406,64 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
return value;
}
void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_state_t* eval_state) {
#ifndef RC_DISABLE_LUA
rc_luapeek_t luapeek;
#endif /* RC_DISABLE_LUA */
/* step 1: read memory */
switch (self->type) {
case RC_OPERAND_CONST:
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = self->value.num;
return;
case RC_OPERAND_FP:
result->type = RC_VALUE_TYPE_FLOAT;
result->value.f32 = (float)self->value.dbl;
return;
case RC_OPERAND_LUA:
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = 0;
#ifndef RC_DISABLE_LUA
if (eval_state->L != 0) {
lua_rawgeti(eval_state->L, LUA_REGISTRYINDEX, self->value.luafunc);
lua_pushcfunction(eval_state->L, rc_luapeek);
luapeek.peek = eval_state->peek;
luapeek.ud = eval_state->peek_userdata;
lua_pushlightuserdata(eval_state->L, &luapeek);
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
if (lua_isboolean(eval_state->L, -1)) {
result->value.u32 = (unsigned)lua_toboolean(eval_state->L, -1);
}
else {
result->value.u32 = (unsigned)lua_tonumber(eval_state->L, -1);
}
}
lua_pop(eval_state->L, 1);
}
#endif /* RC_DISABLE_LUA */
break;
default:
result->type = RC_VALUE_TYPE_UNSIGNED;
result->value.u32 = rc_get_memref_value(self->value.memref, self->type, eval_state);
break;
}
/* step 2: convert read memory to desired format */
rc_transform_memref_value(result, self->size);
/* step 3: apply logic (BCD/invert) */
if (result->type == RC_VALUE_TYPE_UNSIGNED)
result->value.u32 = rc_transform_operand_value(result->value.u32, self);
}
+37 -5
View File
@@ -65,8 +65,26 @@ typedef struct {
}
rc_scratch_t;
enum {
RC_VALUE_TYPE_NONE,
RC_VALUE_TYPE_UNSIGNED,
RC_VALUE_TYPE_SIGNED,
RC_VALUE_TYPE_FLOAT
};
typedef struct {
unsigned add_value; /* AddSource/SubSource */
union {
unsigned u32;
int i32;
float f32;
} value;
char type;
}
rc_typed_value_t;
typedef struct {
rc_typed_value_t add_value;/* AddSource/SubSource */
int add_hits; /* AddHits */
unsigned add_address; /* AddAddress */
@@ -74,7 +92,7 @@ typedef struct {
void* peek_userdata;
lua_State* L;
unsigned measured_value; /* Measured */
rc_typed_value_t measured_value; /* Measured */
char was_reset; /* ResetIf triggered */
char has_hits; /* one of more hit counts is non-zero */
char primed; /* true if all non-Trigger conditions are true */
@@ -118,7 +136,8 @@ void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
void rc_update_memref_value(rc_memref_value_t* memref, unsigned value);
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
char rc_memref_shared_size(char size);
unsigned rc_transform_memref_value(unsigned value, char size);
unsigned rc_memref_mask(char size);
void rc_transform_memref_value(rc_typed_value_t* value, char size);
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_trigger_state_active(int state);
@@ -129,17 +148,30 @@ void rc_reset_condset(rc_condset_t* self);
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_state);
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_condition_is_combining(const rc_condition_t* self);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse);
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state);
void rc_evaluate_operand(rc_typed_value_t* value, rc_operand_t* self, rc_eval_state_t* eval_state);
int rc_operand_is_float_memref(const rc_operand_t* self);
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
void rc_reset_value(rc_value_t* self);
rc_value_t* rc_alloc_helper_variable(const char* memaddr, int memaddr_len, rc_parse_state_t* parse);
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L);
void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_multiply(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amount);
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);
int rc_format_typed_value(char* buffer, int size, const rc_typed_value_t* value, int format);
void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_state_t* parse);
int rc_lboard_state_active(int state);
void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script, rc_parse_state_t* parse);
+56 -9
View File
@@ -31,11 +31,21 @@ static const rc_disallowed_setting_t _rc_disallowed_bsnes_settings[] = {
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_cap32_settings[] = {
{ "cap32_autorun", "disabled" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_dolphin_settings[] = {
{ "dolphin_cheats_enabled", "enabled" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_duckstation_settings[] = {
{ "duckstation_CDROM.LoadImagePatches", "true" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_ecwolf_settings[] = {
{ "ecwolf-invulnerability", "enabled" },
{ NULL, NULL }
@@ -44,6 +54,8 @@ static const rc_disallowed_setting_t _rc_disallowed_ecwolf_settings[] = {
static const rc_disallowed_setting_t _rc_disallowed_fbneo_settings[] = {
{ "fbneo-allow-patched-romsets", "enabled" },
{ "fbneo-cheat-*", "!,Disabled,0 - Disabled" },
{ "fbneo-dipswitch-*", "Universe BIOS*" },
{ "fbneo-neogeo-mode", "UNIBIOS" },
{ NULL, NULL }
};
@@ -95,6 +107,9 @@ static const rc_disallowed_setting_t _rc_disallowed_smsplus_settings[] = {
};
static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = {
{ "snes9x_gfx_clip", "disabled" },
{ "snes9x_gfx_transp", "disabled" },
{ "snes9x_layer_*", "disabled" },
{ "snes9x_region", "pal" },
{ NULL, NULL }
};
@@ -106,7 +121,9 @@ static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] =
static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ "bsnes-mercury", _rc_disallowed_bsnes_settings },
{ "cap32", _rc_disallowed_cap32_settings },
{ "dolphin-emu", _rc_disallowed_dolphin_settings },
{ "DuckStation", _rc_disallowed_duckstation_settings },
{ "ecwolf", _rc_disallowed_ecwolf_settings },
{ "FCEUmm", _rc_disallowed_fceumm_settings },
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings },
@@ -123,10 +140,11 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ NULL, NULL }
};
static int rc_libretro_string_equal_nocase(const char* test, const char* value) {
while (*test) {
if (tolower(*test++) != tolower(*value++))
return 0;
static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char* value) {
char c1, c2;
while ((c1 = *test++)) {
if (tolower(c1) != tolower(c2 = *value++))
return (c2 == '*');
}
return (*value == '\0');
@@ -151,7 +169,7 @@ static int rc_libretro_match_value(const char* val, const char* match) {
char buffer[128];
memcpy(buffer, ptr, size);
buffer[size] = '\0';
if (rc_libretro_string_equal_nocase(buffer, val))
if (rc_libretro_string_equal_nocase_wildcard(buffer, val))
return 1;
}
}
@@ -165,7 +183,7 @@ static int rc_libretro_match_value(const char* val, const char* match) {
return !rc_libretro_match_value(val, &match[1]);
/* just a single value, attempt to match it */
return rc_libretro_string_equal_nocase(val, match);
return rc_libretro_string_equal_nocase_wildcard(val, match);
}
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value) {
@@ -325,11 +343,24 @@ static const struct retro_memory_descriptor* rc_libretro_memory_get_descriptor(c
/* otherwise, attempt to match the address by matching the select bits */
/* address is in the block if (addr & select) == (start & select) */
if (((desc->start ^ real_address) & desc->select) == 0) {
/* calculate the offset within the descriptor, removing any disconnected bits */
*offset = (real_address & ~desc->disconnect) - desc->start;
/* get the relative offset of the address from the start of the memory block */
unsigned reduced_address = real_address - (unsigned)desc->start;
/* remove any bits from the reduced_address that correspond to the bits in the disconnect
* mask and collapse the remaining bits. this code was copied from the mmap_reduce function
* in RetroArch. i'm not exactly sure how it works, but it does. */
unsigned disconnect_mask = (unsigned)desc->disconnect;
while (disconnect_mask) {
const unsigned tmp = (disconnect_mask - 1) & ~disconnect_mask;
reduced_address = (reduced_address & tmp) | ((reduced_address >> 1) & ~tmp);
disconnect_mask = (disconnect_mask & (disconnect_mask - 1)) >> 1;
}
/* calculate the offset within the descriptor */
*offset = reduced_address;
/* sanity check - make sure the descriptor is large enough to hold the target address */
if (*offset < desc->len)
if (reduced_address < desc->len)
return desc;
}
}
@@ -352,6 +383,7 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
const rc_memory_region_t* console_region = &console_regions->region[i];
size_t console_region_size = console_region->end_address - console_region->start_address + 1;
unsigned real_address = console_region->real_address;
unsigned disconnect_size = 0;
while (console_region_size > 0) {
const struct retro_memory_descriptor* desc = rc_libretro_memory_get_descriptor(mmap, real_address, &offset);
@@ -362,6 +394,14 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
rc_libretro_verbose(description);
}
if (disconnect_size && console_region_size > disconnect_size) {
rc_libretro_memory_register_region(regions, console_region->type, NULL, disconnect_size, "null filler");
console_region_size -= disconnect_size;
real_address += disconnect_size;
disconnect_size = 0;
continue;
}
rc_libretro_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
break;
}
@@ -378,6 +418,13 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
}
desc_size = desc->len - offset;
if (desc->disconnect && desc_size > desc->disconnect) {
/* if we need to extract a disconnect bit, the largest block we can read is up to
* the next time that bit flips */
/* https://stackoverflow.com/questions/12247186/find-the-lowest-set-bit */
disconnect_size = (desc->disconnect & -((int)desc->disconnect));
desc_size = disconnect_size - (real_address & (disconnect_size - 1));
}
if (console_region_size > desc_size) {
if (desc_size == 0) {
+168 -50
View File
@@ -8,7 +8,9 @@
enum {
RC_FORMAT_STRING = 101,
RC_FORMAT_LOOKUP = 102,
RC_FORMAT_UNKNOWN_MACRO = 103
RC_FORMAT_UNKNOWN_MACRO = 103,
RC_FORMAT_ASCIICHAR = 104,
RC_FORMAT_UNICODECHAR = 105
};
static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
@@ -73,6 +75,12 @@ static const char* rc_parse_line(const char* line, const char** end, rc_parse_st
return nextline;
}
typedef struct rc_richpresence_builtin_macro_t {
const char* name;
size_t name_len;
unsigned short display_type;
} rc_richpresence_builtin_macro_t;
static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const char* line, const char* endline, rc_parse_state_t* parse, rc_richpresence_lookup_t* first_lookup) {
rc_richpresence_display_t* self;
rc_richpresence_display_part_t* part;
@@ -132,6 +140,8 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
if (*ptr == '@') {
/* handle macro part */
size_t macro_len;
line = ++ptr;
while (ptr < endline && *ptr != '(')
++ptr;
@@ -141,58 +151,81 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
return 0;
}
if (ptr > line) {
/* find the lookup and hook it up */
lookup = first_lookup;
while (lookup) {
if (strncmp(lookup->name, line, ptr - line) == 0 && lookup->name[ptr - line] == '\0') {
part = RC_ALLOC(rc_richpresence_display_part_t, parse);
*next = part;
next = &part->next;
macro_len = ptr - line;
part->text = lookup->name;
part->lookup = lookup;
part->display_type = lookup->format;
part = RC_ALLOC(rc_richpresence_display_part_t, parse);
memset(part, 0, sizeof(rc_richpresence_display_part_t));
*next = part;
next = &part->next;
in = line;
line = ++ptr;
while (ptr < endline && *ptr != ')')
++ptr;
if (*ptr == ')') {
part->value = rc_alloc_helper_variable_memref_value(line, (int)(ptr-line), parse);
if (parse->offset < 0)
return 0;
++ptr;
}
else {
/* non-terminated macro, dump the macro and the remaining portion of the line */
--in; /* already skipped over @ */
part->display_type = RC_FORMAT_STRING;
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
}
part->display_type = RC_FORMAT_UNKNOWN_MACRO;
/* find the lookup and hook it up */
lookup = first_lookup;
while (lookup) {
if (strncmp(lookup->name, line, macro_len) == 0 && lookup->name[macro_len] == '\0') {
part->text = lookup->name;
part->lookup = lookup;
part->display_type = lookup->format;
break;
}
lookup = lookup->next;
}
if (!lookup) {
static const rc_richpresence_builtin_macro_t builtin_macros[] = {
{"Number", 6, RC_FORMAT_VALUE},
{"Score", 5, RC_FORMAT_SCORE},
{"Centiseconds", 12, RC_FORMAT_CENTISECS},
{"Seconds", 7, RC_FORMAT_SECONDS},
{"Minutes", 7, RC_FORMAT_MINUTES},
{"SecondsAsMinutes", 16, RC_FORMAT_SECONDS_AS_MINUTES},
{"ASCIIChar", 9, RC_FORMAT_ASCIICHAR},
{"UnicodeChar", 11, RC_FORMAT_UNICODECHAR},
{"Float1", 6, RC_FORMAT_FLOAT1},
{"Float2", 6, RC_FORMAT_FLOAT2},
{"Float3", 6, RC_FORMAT_FLOAT3},
{"Float4", 6, RC_FORMAT_FLOAT4},
{"Float5", 6, RC_FORMAT_FLOAT5},
{"Float6", 6, RC_FORMAT_FLOAT6},
};
size_t i;
for (i = 0; i < sizeof(builtin_macros) / sizeof(builtin_macros[0]); ++i) {
if (macro_len == builtin_macros[i].name_len &&
memcmp(builtin_macros[i].name, line, builtin_macros[i].name_len) == 0) {
part->text = builtin_macros[i].name;
part->lookup = NULL;
part->display_type = builtin_macros[i].display_type;
break;
}
lookup = lookup->next;
}
}
if (!lookup) {
part = RC_ALLOC(rc_richpresence_display_part_t, parse);
memset(part, 0, sizeof(rc_richpresence_display_part_t));
*next = part;
next = &part->next;
/* find the closing parenthesis */
in = line;
line = ++ptr;
while (ptr < endline && *ptr != ')')
++ptr;
/* find the closing parenthesis */
while (ptr < endline && *ptr != ')')
++ptr;
if (*ptr == ')')
++ptr;
if (*ptr != ')') {
/* non-terminated macro, dump the macro and the remaining portion of the line */
--in; /* already skipped over @ */
part->display_type = RC_FORMAT_STRING;
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
}
else if (part->display_type != RC_FORMAT_UNKNOWN_MACRO) {
part->value = rc_alloc_helper_variable_memref_value(line, (int)(ptr - line), parse);
if (parse->offset < 0)
return 0;
/* assert: the allocated string is going to be smaller than the memory used for the parameter of the macro */
part->display_type = RC_FORMAT_UNKNOWN_MACRO;
part->text = rc_alloc_str(parse, line, (int)(ptr - line));
}
++ptr;
}
else {
/* assert: the allocated string is going to be smaller than the memory used for the parameter of the macro */
++ptr;
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
}
}
@@ -623,11 +656,11 @@ void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, voi
static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part, char* buffer, unsigned buffersize)
{
rc_richpresence_lookup_item_t* item;
rc_typed_value_t value;
char tmp[256];
char* ptr = buffer;
const char* text;
size_t chars;
unsigned value;
*ptr = '\0';
while (part) {
@@ -638,14 +671,16 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
break;
case RC_FORMAT_LOOKUP:
value = part->value->value;
rc_typed_value_from_memref_value(&value, part->value);
rc_typed_value_convert(&value, RC_VALUE_TYPE_UNSIGNED);
text = part->lookup->default_label;
item = part->lookup->root;
while (item) {
if (value > item->last) {
if (value.value.u32 > item->last) {
item = item->right;
}
else if (value < item->first) {
else if (value.value.u32 < item->first) {
item = item->left;
}
else {
@@ -657,14 +692,86 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
chars = strlen(text);
break;
case RC_FORMAT_ASCIICHAR:
chars = 0;
text = tmp;
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_ASCIICHAR)
part = part->next;
break;
}
if (value.value.u32 < 32 || value.value.u32 >= 127)
value.value.u32 = '?';
tmp[chars++] = (char)value.value.u32;
if (chars == sizeof(tmp) || !part->next || part->next->display_type != RC_FORMAT_ASCIICHAR)
break;
part = part->next;
} while (1);
tmp[chars] = '\0';
break;
case RC_FORMAT_UNICODECHAR:
chars = 0;
text = tmp;
value.type = RC_VALUE_TYPE_UNSIGNED;
do {
value.value.u32 = part->value->value;
if (value.value.u32 == 0) {
/* null terminator - skip over remaining character macros */
while (part->next && part->next->display_type == RC_FORMAT_UNICODECHAR)
part = part->next;
break;
}
if (value.value.u32 < 32 || value.value.u32 > 65535)
value.value.u32 = 0xFFFD; /* unicode replacement char */
if (value.value.u32 < 0x80) {
tmp[chars++] = (char)value.value.u32;
}
else if (value.value.u32 < 0x0800) {
tmp[chars + 1] = (char)(0x80 | (value.value.u32 & 0x3F)); value.value.u32 >>= 6;
tmp[chars] = (char)(0xC0 | (value.value.u32 & 0x1F));
chars += 2;
}
else {
/* surrogate pair not supported, convert to replacement char */
if (value.value.u32 >= 0xD800 && value.value.u32 < 0xE000)
value.value.u32 = 0xFFFD;
tmp[chars + 2] = (char)(0x80 | (value.value.u32 & 0x3F)); value.value.u32 >>= 6;
tmp[chars + 1] = (char)(0x80 | (value.value.u32 & 0x3F)); value.value.u32 >>= 6;
tmp[chars] = (char)(0xE0 | (value.value.u32 & 0x1F));
chars += 3;
}
if (chars >= sizeof(tmp) - 3 || !part->next || part->next->display_type != RC_FORMAT_UNICODECHAR)
break;
part = part->next;
} while (1);
tmp[chars] = '\0';
break;
case RC_FORMAT_UNKNOWN_MACRO:
chars = snprintf(tmp, sizeof(tmp), "[Unknown macro]%s", part->text);
text = tmp;
break;
default:
value = part->value->value;
chars = rc_format_value(tmp, sizeof(tmp), value, part->display_type);
rc_typed_value_from_memref_value(&value, part->value);
chars = rc_format_typed_value(tmp, sizeof(tmp), &value, part->display_type);
text = tmp;
break;
}
@@ -715,3 +822,14 @@ int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsi
rc_update_richpresence(richpresence, peek, peek_ud, L);
return rc_get_richpresence_display_string(richpresence, buffer, buffersize, peek, peek_ud, L);
}
void rc_reset_richpresence(rc_richpresence_t* self) {
rc_richpresence_display_t* display;
rc_value_t* variable;
for (display = self->first_display; display; display = display->next)
rc_reset_trigger(&display->trigger);
for (variable = self->variables; variable; variable = variable->next)
rc_reset_value(variable);
}
+49 -14
View File
@@ -300,6 +300,7 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, unsigned id, const char* mema
unsigned char md5[16];
rc_lboard_t* lboard;
rc_parse_state_t parse;
rc_runtime_lboard_t* runtime_lboard;
int size;
unsigned i;
@@ -378,14 +379,15 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, unsigned id, const char* mema
}
/* assign the new lboard */
self->lboards[self->lboard_count].id = id;
self->lboards[self->lboard_count].value = 0;
self->lboards[self->lboard_count].lboard = lboard;
self->lboards[self->lboard_count].buffer = lboard_buffer;
self->lboards[self->lboard_count].invalid_memref = NULL;
memcpy(self->lboards[self->lboard_count].md5, md5, 16);
self->lboards[self->lboard_count].owns_memrefs = rc_runtime_allocated_memrefs(self);
++self->lboard_count;
runtime_lboard = &self->lboards[self->lboard_count++];
runtime_lboard->id = id;
runtime_lboard->value = 0;
runtime_lboard->lboard = lboard;
runtime_lboard->buffer = lboard_buffer;
runtime_lboard->invalid_memref = NULL;
memcpy(runtime_lboard->md5, md5, 16);
runtime_lboard->serialized_size = 0;
runtime_lboard->owns_memrefs = rc_runtime_allocated_memrefs(self);
/* reset it, and return it */
lboard->memrefs = NULL;
@@ -413,17 +415,52 @@ int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format
int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua_State* L, int funcs_idx) {
rc_richpresence_t* richpresence;
rc_runtime_richpresence_t* previous;
rc_richpresence_display_t* display;
rc_runtime_richpresence_t** previous_ptr;
rc_parse_state_t parse;
unsigned char md5[16];
int size;
if (script == NULL)
return RC_MISSING_DISPLAY_STRING;
rc_runtime_checksum(script, md5);
/* look for existing match */
previous_ptr = NULL;
previous = self->richpresence;
while (previous) {
if (previous && memcmp(self->richpresence->md5, md5, 16) == 0) {
/* unchanged. reset all of the conditions */
rc_reset_richpresence(self->richpresence->richpresence);
/* move to front of linked list*/
if (previous_ptr) {
*previous_ptr = previous->previous;
if (!self->richpresence->owns_memrefs) {
free(self->richpresence->buffer);
previous->previous = self->richpresence->previous;
}
else {
previous->previous = self->richpresence;
}
self->richpresence = previous;
}
/* return success*/
return RC_OK;
}
previous_ptr = &previous->previous;
previous = previous->previous;
}
/* no existing match found, parse script */
size = rc_richpresence_size(script);
if (size < 0)
return size;
/* if the previous script doesn't have any memrefs, free it */
previous = self->richpresence;
if (previous) {
if (!previous->owns_memrefs) {
@@ -432,12 +469,14 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
}
}
/* allocate and process the new script */
self->richpresence = (rc_runtime_richpresence_t*)malloc(sizeof(rc_runtime_richpresence_t));
if (!self->richpresence)
return RC_OUT_OF_MEMORY;
self->richpresence->previous = previous;
self->richpresence->owns_memrefs = 0;
memcpy(self->richpresence->md5, md5, sizeof(md5));
self->richpresence->buffer = malloc(size);
if (!self->richpresence->buffer)
@@ -469,11 +508,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
}
else {
/* reset all of the conditions */
display = richpresence->first_display;
while (display != NULL) {
rc_reset_trigger(&display->trigger);
display = display->next;
}
rc_reset_richpresence(richpresence);
}
return RC_OK;
+365 -7
View File
@@ -3,14 +3,18 @@
#include "../rhash/md5.h"
#include <stdlib.h>
#include <string.h>
#define RC_RUNTIME_MARKER 0x0A504152 /* RAP\n */
#define RC_RUNTIME_MARKER 0x0A504152 /* RAP\n */
#define RC_RUNTIME_CHUNK_MEMREFS 0x4645524D /* MREF */
#define RC_RUNTIME_CHUNK_ACHIEVEMENT 0x56484341 /* ACHV */
#define RC_RUNTIME_CHUNK_MEMREFS 0x4645524D /* MREF */
#define RC_RUNTIME_CHUNK_VARIABLES 0x53524156 /* VARS */
#define RC_RUNTIME_CHUNK_ACHIEVEMENT 0x56484341 /* ACHV */
#define RC_RUNTIME_CHUNK_LEADERBOARD 0x4452424C /* LBRD */
#define RC_RUNTIME_CHUNK_RICHPRESENCE 0x48434952 /* RICH */
#define RC_RUNTIME_CHUNK_DONE 0x454E4F44 /* DONE */
#define RC_RUNTIME_CHUNK_DONE 0x454E4F44 /* DONE */
typedef struct rc_runtime_progress_t {
rc_runtime_t* runtime;
@@ -27,6 +31,8 @@ typedef struct rc_runtime_progress_t {
#define RC_MEMREF_FLAG_CHANGED_THIS_FRAME 0x00010000
#define RC_VAR_FLAG_HAS_COND_DATA 0x01000000
#define RC_COND_FLAG_IS_TRUE 0x00000001
#define RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF 0x00010000
#define RC_COND_FLAG_OPERAND1_MEMREF_CHANGED_THIS_FRAME 0x00020000
@@ -75,6 +81,17 @@ static int rc_runtime_progress_match_md5(rc_runtime_progress_t* progress, unsign
return result;
}
static unsigned rc_runtime_progress_djb2(const char* input)
{
unsigned result = 5381;
char c;
while ((c = *input++) != '\0')
result = ((result << 5) + result) + c; /* result = result * 33 + c */
return result;
}
static void rc_runtime_progress_start_chunk(rc_runtime_progress_t* progress, unsigned chunk_id)
{
rc_runtime_progress_write_uint(progress, chunk_id);
@@ -280,7 +297,158 @@ static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_
return RC_OK;
}
static int rc_runtime_progress_write_trigger(rc_runtime_progress_t* progress, rc_trigger_t* trigger)
static unsigned rc_runtime_progress_should_serialize_variable_condset(const rc_condset_t* conditions)
{
const rc_condition_t* condition;
/* predetermined presence of pause flag or indirect memrefs - must serialize */
if (conditions->has_pause || conditions->has_indirect_memrefs)
return RC_VAR_FLAG_HAS_COND_DATA;
/* if any conditions has required hits, must serialize */
/* ASSERT: Measured with comparison and no explicit target will set hit target to 0xFFFFFFFF */
for (condition = conditions->conditions; condition; condition = condition->next) {
if (condition->required_hits > 0)
return RC_VAR_FLAG_HAS_COND_DATA;
}
/* can safely be reset without affecting behavior */
return 0;
}
static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, const rc_value_t* variable)
{
unsigned flags;
flags = rc_runtime_progress_should_serialize_variable_condset(variable->conditions);
if (variable->value.changed)
flags |= RC_MEMREF_FLAG_CHANGED_THIS_FRAME;
rc_runtime_progress_write_uint(progress, flags);
rc_runtime_progress_write_uint(progress, variable->value.value);
rc_runtime_progress_write_uint(progress, variable->value.prior);
if (flags & RC_VAR_FLAG_HAS_COND_DATA) {
int result = rc_runtime_progress_write_condset(progress, variable->conditions);
if (result != RC_OK)
return result;
}
return RC_OK;
}
static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
{
unsigned count = 0;
const rc_value_t* variable;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (count == 0)
return RC_OK;
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_VARIABLES);
rc_runtime_progress_write_uint(progress, count);
for (variable = progress->runtime->variables; variable; variable = variable->next)
{
unsigned djb2 = rc_runtime_progress_djb2(variable->name);
rc_runtime_progress_write_uint(progress, djb2);
rc_runtime_progress_write_variable(progress, variable);
}
rc_runtime_progress_end_chunk(progress);
return RC_OK;
}
static int rc_runtime_progress_read_variable(rc_runtime_progress_t* progress, rc_value_t* variable)
{
unsigned flags = rc_runtime_progress_read_uint(progress);
variable->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
variable->value.value = rc_runtime_progress_read_uint(progress);
variable->value.prior = rc_runtime_progress_read_uint(progress);
if (flags & RC_VAR_FLAG_HAS_COND_DATA) {
int result = rc_runtime_progress_read_condset(progress, variable->conditions);
if (result != RC_OK)
return result;
}
else {
rc_reset_condset(variable->conditions);
}
return RC_OK;
}
static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
{
struct rc_pending_value_t
{
rc_value_t* variable;
unsigned djb2;
};
struct rc_pending_value_t local_pending_variables[32];
struct rc_pending_value_t* pending_variables;
rc_value_t* variable;
unsigned count, serialized_count;
int result;
unsigned i;
serialized_count = rc_runtime_progress_read_uint(progress);
if (serialized_count == 0)
return RC_OK;
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next)
++count;
if (count == 0)
return RC_OK;
if (count <= sizeof(local_pending_variables) / sizeof(local_pending_variables[0])) {
pending_variables = local_pending_variables;
}
else {
pending_variables = (struct rc_pending_value_t*)malloc(count * sizeof(struct rc_pending_value_t));
if (pending_variables == NULL)
return RC_OUT_OF_MEMORY;
}
count = 0;
for (variable = progress->runtime->variables; variable; variable = variable->next) {
pending_variables[count].variable = variable;
pending_variables[count].djb2 = rc_runtime_progress_djb2(variable->name);
++count;
}
result = RC_OK;
for (; serialized_count > 0 && result == RC_OK; --serialized_count) {
unsigned djb2 = rc_runtime_progress_read_uint(progress);
for (i = 0; i < count; ++i) {
if (pending_variables[i].djb2 == djb2) {
variable = pending_variables[i].variable;
result = rc_runtime_progress_read_variable(progress, variable);
if (result == RC_OK) {
if (i < count - 1)
memcpy(&pending_variables[i], &pending_variables[count - 1], sizeof(struct rc_pending_value_t));
count--;
}
break;
}
}
}
while (count > 0)
rc_reset_value(pending_variables[--count].variable);
if (pending_variables != local_pending_variables)
free(pending_variables);
return result;
}
static int rc_runtime_progress_write_trigger(rc_runtime_progress_t* progress, const rc_trigger_t* trigger)
{
rc_condset_t* condset;
int result;
@@ -394,6 +562,153 @@ static int rc_runtime_progress_read_achievement(rc_runtime_progress_t* progress)
return RC_OK;
}
static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progress)
{
unsigned i;
unsigned flags;
int offset = 0;
int result;
for (i = 0; i < progress->runtime->lboard_count; ++i) {
rc_runtime_lboard_t* runtime_lboard = &progress->runtime->lboards[i];
if (!runtime_lboard->lboard)
continue;
/* don't store state for inactive leaderboards */
if (!rc_lboard_state_active(runtime_lboard->lboard->state))
continue;
if (!progress->buffer) {
if (runtime_lboard->serialized_size) {
progress->offset += runtime_lboard->serialized_size;
continue;
}
offset = progress->offset;
}
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_LEADERBOARD);
rc_runtime_progress_write_uint(progress, runtime_lboard->id);
rc_runtime_progress_write_md5(progress, runtime_lboard->md5);
flags = runtime_lboard->lboard->state;
rc_runtime_progress_write_uint(progress, flags);
result = rc_runtime_progress_write_trigger(progress, &runtime_lboard->lboard->start);
if (result != RC_OK)
return result;
result = rc_runtime_progress_write_trigger(progress, &runtime_lboard->lboard->submit);
if (result != RC_OK)
return result;
result = rc_runtime_progress_write_trigger(progress, &runtime_lboard->lboard->cancel);
if (result != RC_OK)
return result;
result = rc_runtime_progress_write_variable(progress, &runtime_lboard->lboard->value);
if (result != RC_OK)
return result;
rc_runtime_progress_end_chunk(progress);
if (!progress->buffer)
runtime_lboard->serialized_size = progress->offset - offset;
}
return RC_OK;
}
static int rc_runtime_progress_read_leaderboard(rc_runtime_progress_t* progress)
{
unsigned id = rc_runtime_progress_read_uint(progress);
unsigned i;
int result;
for (i = 0; i < progress->runtime->lboard_count; ++i) {
rc_runtime_lboard_t* runtime_lboard = &progress->runtime->lboards[i];
if (runtime_lboard->id == id && runtime_lboard->lboard != NULL) {
/* ignore triggered and waiting achievements */
if (runtime_lboard->lboard->state == RC_TRIGGER_STATE_UNUPDATED) {
/* only update state if definition hasn't changed (md5 matches) */
if (rc_runtime_progress_match_md5(progress, runtime_lboard->md5)) {
unsigned flags = rc_runtime_progress_read_uint(progress);
result = rc_runtime_progress_read_trigger(progress, &runtime_lboard->lboard->start);
if (result != RC_OK)
return result;
result = rc_runtime_progress_read_trigger(progress, &runtime_lboard->lboard->submit);
if (result != RC_OK)
return result;
result = rc_runtime_progress_read_trigger(progress, &runtime_lboard->lboard->cancel);
if (result != RC_OK)
return result;
result = rc_runtime_progress_read_variable(progress, &runtime_lboard->lboard->value);
if (result != RC_OK)
return result;
runtime_lboard->lboard->state = (char)(flags & 0x7F);
}
break;
}
}
}
return RC_OK;
}
static int rc_runtime_progress_write_rich_presence(rc_runtime_progress_t* progress)
{
const rc_richpresence_display_t* display;
int result;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
/* if there are no conditional display strings, there's nothing to capture */
display = progress->runtime->richpresence->richpresence->first_display;
if (!display->next)
return RC_OK;
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_RICHPRESENCE);
rc_runtime_progress_write_md5(progress, progress->runtime->richpresence->md5);
for (; display->next; display = display->next) {
result = rc_runtime_progress_write_trigger(progress, &display->trigger);
if (result != RC_OK)
return result;
}
rc_runtime_progress_end_chunk(progress);
return RC_OK;
}
static int rc_runtime_progress_read_rich_presence(rc_runtime_progress_t* progress)
{
rc_richpresence_display_t* display;
int result;
if (!progress->runtime->richpresence || !progress->runtime->richpresence->richpresence)
return RC_OK;
if (!rc_runtime_progress_match_md5(progress, progress->runtime->richpresence->md5)) {
rc_reset_richpresence(progress->runtime->richpresence->richpresence);
return RC_OK;
}
display = progress->runtime->richpresence->richpresence->first_display;
for (; display->next; display = display->next) {
result = rc_runtime_progress_read_trigger(progress, &display->trigger);
if (result != RC_OK)
return result;
}
return RC_OK;
}
static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progress)
{
md5_state_t state;
@@ -405,9 +720,18 @@ static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progres
if ((result = rc_runtime_progress_write_memrefs(progress)) != RC_OK)
return result;
if ((result = rc_runtime_progress_write_variables(progress)) != RC_OK)
return result;
if ((result = rc_runtime_progress_write_achievements(progress)) != RC_OK)
return result;
if ((result = rc_runtime_progress_write_leaderboards(progress)) != RC_OK)
return result;
if ((result = rc_runtime_progress_write_rich_presence(progress)) != RC_OK)
return result;
rc_runtime_progress_write_uint(progress, RC_RUNTIME_CHUNK_DONE);
rc_runtime_progress_write_uint(progress, 16);
@@ -455,6 +779,7 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
unsigned chunk_size;
unsigned next_chunk_offset;
unsigned i;
int seen_rich_presence = 0;
int result = RC_OK;
rc_runtime_progress_init(&progress, runtime, L);
@@ -469,8 +794,7 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
rc_runtime_trigger_t* runtime_trigger = &runtime->triggers[i];
if (runtime_trigger->trigger) {
/* don't update state for inactive or triggered achievements */
if (rc_trigger_state_active(runtime_trigger->trigger->state))
{
if (rc_trigger_state_active(runtime_trigger->trigger->state)) {
/* mark active achievements as unupdated. anything that's still unupdated
* after deserializing the progress will be reset to waiting */
runtime_trigger->trigger->state = RC_TRIGGER_STATE_UNUPDATED;
@@ -478,6 +802,18 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
}
}
for (i = 0; i < runtime->lboard_count; ++i) {
rc_runtime_lboard_t* runtime_lboard = &runtime->lboards[i];
if (runtime_lboard->lboard) {
/* don't update state for inactive or triggered achievements */
if (rc_lboard_state_active(runtime_lboard->lboard->state)) {
/* mark active achievements as unupdated. anything that's still unupdated
* after deserializing the progress will be reset to waiting */
runtime_lboard->lboard->state = RC_TRIGGER_STATE_UNUPDATED;
}
}
}
do {
chunk_id = rc_runtime_progress_read_uint(&progress);
chunk_size = rc_runtime_progress_read_uint(&progress);
@@ -489,10 +825,23 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
result = rc_runtime_progress_read_memrefs(&progress);
break;
case RC_RUNTIME_CHUNK_VARIABLES:
result = rc_runtime_progress_read_variables(&progress);
break;
case RC_RUNTIME_CHUNK_ACHIEVEMENT:
result = rc_runtime_progress_read_achievement(&progress);
break;
case RC_RUNTIME_CHUNK_LEADERBOARD:
result = rc_runtime_progress_read_leaderboard(&progress);
break;
case RC_RUNTIME_CHUNK_RICHPRESENCE:
seen_rich_presence = 1;
result = rc_runtime_progress_read_rich_presence(&progress);
break;
case RC_RUNTIME_CHUNK_DONE:
md5_init(&state);
md5_append(&state, progress.buffer, progress.offset);
@@ -519,6 +868,15 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
if (trigger && trigger->state == RC_TRIGGER_STATE_UNUPDATED)
rc_reset_trigger(trigger);
}
for (i = 0; i < runtime->lboard_count; ++i) {
rc_lboard_t* lboard = runtime->lboards[i].lboard;
if (lboard && lboard->state == RC_TRIGGER_STATE_UNUPDATED)
rc_reset_lboard(lboard);
}
if (!seen_rich_presence && runtime->richpresence && runtime->richpresence->richpresence)
rc_reset_richpresence(runtime->richpresence->richpresence);
}
return result;
+4 -2
View File
@@ -179,8 +179,10 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
}
/* if paused, the measured value may not be captured, keep the old value */
if (!is_paused)
self->measured_value = eval_state.measured_value;
if (!is_paused) {
rc_typed_value_convert(&eval_state.measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = eval_state.measured_value.value.u32;
}
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
/* otherwise, if the state is WAITING, proceed to activating the trigger */
+418 -50
View File
@@ -2,6 +2,7 @@
#include <string.h> /* memset */
#include <ctype.h> /* isdigit */
#include <float.h> /* FLT_EPSILON */
static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
rc_condset_t** next_clause;
@@ -43,28 +44,26 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
char buffer[64] = "A:";
const char* buffer_ptr;
char* ptr;
int end_of_clause;
/* convert legacy format into condset */
self->conditions = RC_ALLOC(rc_condset_t, parse);
self->conditions->has_pause = 0;
self->conditions->is_paused = 0;
memset(self->conditions, 0, sizeof(rc_condset_t));
next = &self->conditions->conditions;
next_clause = &self->conditions->next;
for (;;) {
for (;; ++(*memaddr)) {
buffer[0] = 'A'; /* reset to AddSource */
ptr = &buffer[2];
end_of_clause = 0;
do {
/* extract the next clause */
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
end_of_clause = 1;
*ptr = '\0';
break;
@@ -72,24 +71,31 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-' || *buffer_ptr == '+')
++buffer_ptr; /* ignore sign */
if (*buffer_ptr == '-') {
buffer[0] = 'B'; /* change to SubSource */
++(*memaddr); /* don't copy sign */
++buffer_ptr; /* ignore sign when doing floating point check */
}
else if (*buffer_ptr == '+') {
++buffer_ptr; /* ignore sign when doing floating point check */
}
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
break;
continue;
default:
*ptr++ = **memaddr;
break;
continue;
}
++(*memaddr);
} while (!end_of_clause);
break;
}
/* process the clause */
buffer_ptr = buffer;
cond = rc_parse_condition(&buffer_ptr, parse, 0);
if (parse->offset < 0)
@@ -113,31 +119,40 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
return;
}
cond->pause = 0;
*next = cond;
switch ((*memaddr)[-1]) {
case '_': /* add next */
next = &cond->next;
break;
case '$': /* max of */
cond->type = RC_CONDITION_MEASURED;
cond->next = 0;
*next_clause = RC_ALLOC(rc_condset_t, parse);
(*next_clause)->has_pause = 0;
(*next_clause)->is_paused = 0;
next = &(*next_clause)->conditions;
next_clause = &(*next_clause)->next;
break;
default: /* end of valid string */
--(*memaddr); /* undo the increment we performed when copying the string */
cond->type = RC_CONDITION_MEASURED;
cond->next = 0;
*next_clause = 0;
return;
if (**memaddr == '_') {
/* add next */
next = &cond->next;
continue;
}
if (cond->type == RC_CONDITION_SUB_SOURCE) {
/* cannot change SubSource to Measured. add a dummy condition */
next = &cond->next;
buffer_ptr = "A:0";
cond = rc_parse_condition(&buffer_ptr, parse, 0);
*next = cond;
}
/* convert final AddSource condition to Measured */
cond->type = RC_CONDITION_MEASURED;
cond->next = 0;
if (**memaddr != '$') {
/* end of valid string */
*next_clause = 0;
break;
}
/* max of ($), start a new clause */
*next_clause = RC_ALLOC(rc_condset_t, parse);
if (parse->buffer) /* don't clear in sizing mode or pointer will break */
memset(*next_clause, 0, sizeof(rc_condset_t));
next = &(*next_clause)->conditions;
next_clause = &(*next_clause)->next;
}
}
@@ -188,14 +203,16 @@ rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int
return (parse.offset >= 0) ? self : NULL;
}
int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L) {
rc_eval_state_t eval_state;
rc_condset_t* condset;
int result = 0;
int paused = 1;
int valid = 0;
rc_update_memref_values(self->memrefs, peek, ud);
value->value.i32 = 0;
value->type = RC_VALUE_TYPE_SIGNED;
for (condset = self->conditions; condset != NULL; condset = condset->next) {
memset(&eval_state, 0, sizeof(eval_state));
eval_state.peek = peek;
@@ -214,34 +231,46 @@ int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L)
rc_reset_condset(condset);
/* if the measured value came from a hit count, reset it too */
if (eval_state.measured_from_hits)
eval_state.measured_value = 0;
if (eval_state.measured_from_hits) {
eval_state.measured_value.value.u32 = 0;
eval_state.measured_value.type = RC_VALUE_TYPE_UNSIGNED;
}
}
if (paused) {
if (!valid) {
/* capture the first valid measurement */
result = (int)eval_state.measured_value;
paused = 0;
memcpy(value, &eval_state.measured_value, sizeof(*value));
valid = 1;
}
else {
/* multiple condsets are currently only used for the MAX_OF operation.
* only keep the condset's value if it's higher than the current highest value.
*/
if ((int)eval_state.measured_value > result)
result = (int)eval_state.measured_value;
if (rc_typed_value_compare(&eval_state.measured_value, value, RC_OPERATOR_GT))
memcpy(value, &eval_state.measured_value, sizeof(*value));
}
}
if (!paused) {
return valid;
}
int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
rc_typed_value_t result;
int valid = rc_evaluate_value_typed(self, &result, peek, ud, L);
if (valid) {
/* if not paused, store the value so that it's available when paused. */
rc_update_memref_value(&self->value, result);
rc_typed_value_convert(&result, RC_VALUE_TYPE_UNSIGNED);
rc_update_memref_value(&self->value, result.value.u32);
}
else {
/* when paused, the Measured value will not be captured, use the last captured value. */
result = self->value.value;
result.value.u32 = self->value.value;
result.type = RC_VALUE_TYPE_UNSIGNED;
}
return result;
rc_typed_value_convert(&result, RC_VALUE_TYPE_SIGNED);
return result.value.i32;
}
void rc_reset_value(rc_value_t* self) {
@@ -309,8 +338,347 @@ rc_value_t* rc_alloc_helper_variable(const char* memaddr, int memaddr_len, rc_pa
}
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L) {
rc_typed_value_t result;
while (variable) {
rc_evaluate_value(variable, peek, ud, L);
if (rc_evaluate_value_typed(variable, &result, peek, ud, L)) {
/* store the raw bytes and type to be restored by rc_typed_value_from_memref_value */
rc_update_memref_value(&variable->value, result.value.u32);
variable->value.type = result.type;
}
variable = variable->next;
}
}
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref) {
value->value.u32 = memref->value;
if (memref->size == RC_MEMSIZE_VARIABLE) {
/* a variable can be any of the supported types, but the raw data was copied into u32 */
value->type = memref->type;
}
else {
/* not a variable, only u32 is supported */
value->type = RC_VALUE_TYPE_UNSIGNED;
}
}
void rc_typed_value_convert(rc_typed_value_t* value, char new_type) {
switch (new_type) {
case RC_VALUE_TYPE_UNSIGNED:
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED:
return;
case RC_VALUE_TYPE_SIGNED:
value->value.u32 = (unsigned)value->value.i32;
break;
case RC_VALUE_TYPE_FLOAT:
value->value.u32 = (unsigned)value->value.f32;
break;
default:
value->value.u32 = 0;
break;
}
break;
case RC_VALUE_TYPE_SIGNED:
switch (value->type) {
case RC_VALUE_TYPE_SIGNED:
return;
case RC_VALUE_TYPE_UNSIGNED:
value->value.i32 = (int)value->value.u32;
break;
case RC_VALUE_TYPE_FLOAT:
value->value.i32 = (int)value->value.f32;
break;
default:
value->value.i32 = 0;
break;
}
break;
case RC_VALUE_TYPE_FLOAT:
switch (value->type) {
case RC_VALUE_TYPE_FLOAT:
return;
case RC_VALUE_TYPE_UNSIGNED:
value->value.f32 = (float)value->value.u32;
break;
case RC_VALUE_TYPE_SIGNED:
value->value.f32 = (float)value->value.i32;
break;
default:
value->value.f32 = 0.0;
break;
}
break;
default:
break;
}
value->type = new_type;
}
static rc_typed_value_t* rc_typed_value_convert_into(rc_typed_value_t* dest, const rc_typed_value_t* source, char new_type) {
memcpy(dest, source, sizeof(rc_typed_value_t));
rc_typed_value_convert(dest, new_type);
return dest;
}
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
if (amount->type != value->type && value->type != RC_VALUE_TYPE_NONE)
amount = rc_typed_value_convert_into(&converted, amount, value->type);
switch (value->type)
{
case RC_VALUE_TYPE_UNSIGNED:
value->value.u32 += amount->value.u32;
break;
case RC_VALUE_TYPE_SIGNED:
value->value.i32 += amount->value.i32;
break;
case RC_VALUE_TYPE_FLOAT:
value->value.f32 += amount->value.f32;
break;
case RC_VALUE_TYPE_NONE:
memcpy(value, amount, sizeof(rc_typed_value_t));
break;
default:
break;
}
}
void rc_typed_value_multiply(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
switch (value->type)
{
case RC_VALUE_TYPE_UNSIGNED:
switch (amount->type)
{
case RC_VALUE_TYPE_UNSIGNED:
/* the c standard for unsigned multiplication is well defined as non-overflowing truncation
* to the type's size. this allows negative multiplication through twos-complements. i.e.
* 1 * -1 (0xFFFFFFFF) = 0xFFFFFFFF = -1
* 3 * -2 (0xFFFFFFFE) = 0x2FFFFFFFA & 0xFFFFFFFF = 0xFFFFFFFA = -6
* 10 * -5 (0xFFFFFFFB) = 0x9FFFFFFCE & 0xFFFFFFFF = 0xFFFFFFCE = -50
*/
value->value.u32 *= amount->value.u32;
break;
case RC_VALUE_TYPE_SIGNED:
value->value.u32 *= (unsigned)amount->value.i32;
break;
case RC_VALUE_TYPE_FLOAT:
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
value->value.f32 *= amount->value.f32;
break;
default:
value->type = RC_VALUE_TYPE_NONE;
break;
}
break;
case RC_VALUE_TYPE_SIGNED:
switch (amount->type)
{
case RC_VALUE_TYPE_SIGNED:
value->value.i32 *= amount->value.i32;
break;
case RC_VALUE_TYPE_UNSIGNED:
value->value.i32 *= (int)amount->value.u32;
break;
case RC_VALUE_TYPE_FLOAT:
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
value->value.f32 *= amount->value.f32;
break;
default:
value->type = RC_VALUE_TYPE_NONE;
break;
}
break;
case RC_VALUE_TYPE_FLOAT:
if (amount->type == RC_VALUE_TYPE_NONE) {
value->type = RC_VALUE_TYPE_NONE;
}
else {
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
value->value.f32 *= amount->value.f32;
}
break;
default:
value->type = RC_VALUE_TYPE_NONE;
break;
}
}
void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
switch (amount->type)
{
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 /= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 /= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 /= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 /= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
if (amount->value.f32 == 0.0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
value->value.f32 /= amount->value.f32;
}
static int rc_typed_value_compare_floats(float f1, float f2, char oper) {
if (f1 == f2) {
/* exactly equal */
}
else {
/* attempt to match 7 significant digits (24-bit mantissa supports just over 7 significant decimal digits) */
/* https://stackoverflow.com/questions/17333/what-is-the-most-effective-way-for-float-and-double-comparison */
const float abs1 = (f1 < 0) ? -f1 : f1;
const float abs2 = (f2 < 0) ? -f2 : f2;
const float threshold = ((abs1 < abs2) ? abs1 : abs2) * FLT_EPSILON;
const float diff = f1 - f2;
const float abs_diff = (diff < 0) ? -diff : diff;
if (abs_diff <= threshold) {
/* approximately equal */
}
else if (diff > threshold) {
/* greater */
switch (oper) {
case RC_OPERATOR_NE:
case RC_OPERATOR_GT:
case RC_OPERATOR_GE:
return 1;
default:
return 0;
}
}
else {
/* lesser */
switch (oper) {
case RC_OPERATOR_NE:
case RC_OPERATOR_LT:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
}
/* exactly or approximately equal */
switch (oper) {
case RC_OPERATOR_EQ:
case RC_OPERATOR_GE:
case RC_OPERATOR_LE:
return 1;
default:
return 0;
}
}
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper) {
rc_typed_value_t converted_value2;
if (value2->type != value1->type)
value2 = rc_typed_value_convert_into(&converted_value2, value2, value1->type);
switch (value1->type) {
case RC_VALUE_TYPE_UNSIGNED:
switch (oper) {
case RC_OPERATOR_EQ: return value1->value.u32 == value2->value.u32;
case RC_OPERATOR_NE: return value1->value.u32 != value2->value.u32;
case RC_OPERATOR_LT: return value1->value.u32 < value2->value.u32;
case RC_OPERATOR_LE: return value1->value.u32 <= value2->value.u32;
case RC_OPERATOR_GT: return value1->value.u32 > value2->value.u32;
case RC_OPERATOR_GE: return value1->value.u32 >= value2->value.u32;
default: return 1;
}
case RC_VALUE_TYPE_SIGNED:
switch (oper) {
case RC_OPERATOR_EQ: return value1->value.i32 == value2->value.i32;
case RC_OPERATOR_NE: return value1->value.i32 != value2->value.i32;
case RC_OPERATOR_LT: return value1->value.i32 < value2->value.i32;
case RC_OPERATOR_LE: return value1->value.i32 <= value2->value.i32;
case RC_OPERATOR_GT: return value1->value.i32 > value2->value.i32;
case RC_OPERATOR_GE: return value1->value.i32 >= value2->value.i32;
default: return 1;
}
case RC_VALUE_TYPE_FLOAT:
return rc_typed_value_compare_floats(value1->value.f32, value2->value.f32, oper);
default:
return 1;
}
}
+852
View File
@@ -0,0 +1,852 @@
#include "rc_hash.h"
#include "../rcheevos/rc_compat.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/* internal helper functions in hash.c */
extern void* rc_file_open(const char* path);
extern void rc_file_seek(void* file_handle, int64_t offset, int origin);
extern int64_t rc_file_tell(void* file_handle);
extern size_t rc_file_read(void* file_handle, void* buffer, int requested_bytes);
extern void rc_file_close(void* file_handle);
extern int rc_hash_error(const char* message);
extern const char* rc_path_get_filename(const char* path);
extern int rc_path_compare_extension(const char* path, const char* ext);
extern rc_hash_message_callback verbose_message_callback;
struct cdrom_t
{
void* file_handle; /* the file handle for reading the track data */
int sector_size; /* the size of each sector in the track data */
int sector_header_size; /* the offset to the raw data within a sector block */
int64_t file_track_offset;/* the offset of the track data within the file */
int track_first_sector; /* the first absolute sector associated to the track (includes pregap) */
int track_pregap_sectors; /* the number of pregap sectors */
#ifndef NDEBUG
uint32_t track_id; /* the index of the track */
#endif
};
static int cdreader_get_sector(unsigned char header[16])
{
int minutes = (header[12] >> 4) * 10 + (header[12] & 0x0F);
int seconds = (header[13] >> 4) * 10 + (header[13] & 0x0F);
int frames = (header[14] >> 4) * 10 + (header[14] & 0x0F);
/* convert the MSF value to a sector index, and subtract 150 (2 seconds) per:
* For data and mixed mode media (those conforming to ISO/IEC 10149), logical block address
* zero shall be assigned to the block at MSF address 00/02/00 */
return ((minutes * 60) + seconds) * 75 + frames - 150;
}
static void cdreader_determine_sector_size(struct cdrom_t* cdrom)
{
/* Attempt to determine the sector and header sizes. The CUE file may be lying.
* Look for the sync pattern using each of the supported sector sizes.
* Then check for the presence of "CD001", which is gauranteed to be in either the
* boot record or primary volume descriptor, one of which is always at sector 16.
*/
const unsigned char sync_pattern[] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
};
unsigned char header[32];
const int64_t toc_sector = 16 + cdrom->track_pregap_sectors;
cdrom->sector_size = 0;
cdrom->sector_header_size = 0;
rc_file_seek(cdrom->file_handle, toc_sector * 2352 + cdrom->file_track_offset, SEEK_SET);
if (rc_file_read(cdrom->file_handle, header, sizeof(header)) < sizeof(header))
return;
if (memcmp(header, sync_pattern, 12) == 0)
{
cdrom->sector_size = 2352;
if (memcmp(&header[25], "CD001", 5) == 0)
cdrom->sector_header_size = 24;
else
cdrom->sector_header_size = 16;
cdrom->track_first_sector = cdreader_get_sector(header) - (int)toc_sector;
}
else
{
rc_file_seek(cdrom->file_handle, toc_sector * 2336 + cdrom->file_track_offset, SEEK_SET);
rc_file_read(cdrom->file_handle, header, sizeof(header));
if (memcmp(header, sync_pattern, 12) == 0)
{
cdrom->sector_size = 2336;
if (memcmp(&header[25], "CD001", 5) == 0)
cdrom->sector_header_size = 24;
else
cdrom->sector_header_size = 16;
cdrom->track_first_sector = cdreader_get_sector(header) - (int)toc_sector;
}
else
{
rc_file_seek(cdrom->file_handle, toc_sector * 2048 + cdrom->file_track_offset, SEEK_SET);
rc_file_read(cdrom->file_handle, header, sizeof(header));
if (memcmp(&header[1], "CD001", 5) == 0)
{
cdrom->sector_size = 2048;
cdrom->sector_header_size = 0;
}
}
}
}
static void* cdreader_open_bin_track(const char* path, uint32_t track)
{
void* file_handle;
struct cdrom_t* cdrom;
if (track > 1)
{
if (verbose_message_callback)
verbose_message_callback("Cannot locate secondary tracks without a cue sheet");
return NULL;
}
file_handle = rc_file_open(path);
if (!file_handle)
return NULL;
cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom));
cdrom->file_handle = file_handle;
#ifndef NDEBUG
cdrom->track_id = track;
#endif
cdreader_determine_sector_size(cdrom);
if (cdrom->sector_size == 0)
{
int64_t size;
rc_file_seek(cdrom->file_handle, 0, SEEK_END);
size = rc_file_tell(cdrom->file_handle);
if ((size % 2352) == 0)
{
/* raw tracks use all 2352 bytes and have a 24 byte header */
cdrom->sector_size = 2352;
cdrom->sector_header_size = 24;
}
else if ((size % 2048) == 0)
{
/* cooked tracks eliminate all header/footer data */
cdrom->sector_size = 2048;
cdrom->sector_header_size = 0;
}
else if ((size % 2336) == 0)
{
/* MODE 2 format without 16-byte sync data */
cdrom->sector_size = 2336;
cdrom->sector_header_size = 8;
}
else
{
free(cdrom);
if (verbose_message_callback)
verbose_message_callback("Could not determine sector size");
return NULL;
}
}
return cdrom;
}
static int cdreader_open_bin(struct cdrom_t* cdrom, const char* path, const char* mode)
{
cdrom->file_handle = rc_file_open(path);
if (!cdrom->file_handle)
return 0;
/* determine sector size */
cdreader_determine_sector_size(cdrom);
/* could not determine, which means we'll probably have more issues later
* but use the CUE provided information anyway
*/
if (cdrom->sector_size == 0)
{
/* All of these modes have 2048 byte payloads. In MODE1/2352 and MODE2/2352
* modes, the mode can actually be specified per sector to change the payload
* size, but that reduces the ability to recover from errors when the disc
* is damaged, so it's seldomly used, and when it is, it's mostly for audio
* or video data where a blip or two probably won't be noticed by the user.
* So, while we techincally support all of the following modes, we only do
* so with 2048 byte payloads.
* http://totalsonicmastering.com/cuesheetsyntax.htm
* MODE1/2048 ? CDROM Mode1 Data (cooked) [no header, no footer]
* MODE1/2352 ? CDROM Mode1 Data (raw) [16 byte header, 288 byte footer]
* MODE2/2336 ? CDROM-XA Mode2 Data [8 byte header, 280 byte footer]
* MODE2/2352 ? CDROM-XA Mode2 Data [24 byte header, 280 byte footer]
*/
if (memcmp(mode, "MODE2/2352", 10) == 0)
{
cdrom->sector_size = 2352;
cdrom->sector_header_size = 24;
}
else if (memcmp(mode, "MODE1/2048", 10) == 0)
{
cdrom->sector_size = 2048;
cdrom->sector_header_size = 0;
}
else if (memcmp(mode, "MODE2/2336", 10) == 0)
{
cdrom->sector_size = 2336;
cdrom->sector_header_size = 8;
}
else if (memcmp(mode, "MODE1/2352", 10) == 0)
{
cdrom->sector_size = 2352;
cdrom->sector_header_size = 16;
}
else if (memcmp(mode, "AUDIO", 5) == 0)
{
cdrom->sector_size = 2352;
cdrom->sector_header_size = 0;
}
}
return (cdrom->sector_size != 0);
}
static char* cdreader_get_bin_path(const char* cue_path, const char* bin_name)
{
const char* filename = rc_path_get_filename(cue_path);
const size_t bin_name_len = strlen(bin_name);
const size_t cue_path_len = filename - cue_path;
const size_t needed = cue_path_len + bin_name_len + 1;
char* bin_filename = (char*)malloc(needed);
if (!bin_filename)
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)needed);
rc_hash_error((const char*)buffer);
}
else
{
memcpy(bin_filename, cue_path, cue_path_len);
memcpy(bin_filename + cue_path_len, bin_name, bin_name_len + 1);
}
return bin_filename;
}
static int64_t cdreader_get_bin_size(const char* cue_path, const char* bin_name)
{
int64_t size = 0;
char* bin_filename = cdreader_get_bin_path(cue_path, bin_name);
if (bin_filename)
{
/* disable verbose messaging while getting file size */
rc_hash_message_callback old_verbose_message_callback = verbose_message_callback;
void* file_handle;
verbose_message_callback = NULL;
file_handle = rc_file_open(bin_filename);
if (file_handle)
{
rc_file_seek(file_handle, 0, SEEK_END);
size = rc_file_tell(file_handle);
rc_file_close(file_handle);
}
verbose_message_callback = old_verbose_message_callback;
free(bin_filename);
}
return size;
}
static void* cdreader_open_cue_track(const char* path, uint32_t track)
{
void* cue_handle;
int64_t cue_offset = 0;
char buffer[1024];
char* bin_filename = NULL;
char *ptr, *ptr2, *end;
int done = 0;
size_t num_read = 0;
struct cdrom_t* cdrom = NULL;
struct track_t
{
uint32_t id;
int sector_size;
int sector_count;
int first_sector;
int pregap_sectors;
int is_data;
int file_track_offset;
int file_first_sector;
char mode[16];
char filename[256];
} current_track, previous_track, largest_track;
cue_handle = rc_file_open(path);
if (!cue_handle)
return NULL;
memset(&current_track, 0, sizeof(current_track));
memset(&previous_track, 0, sizeof(previous_track));
memset(&largest_track, 0, sizeof(largest_track));
do
{
num_read = rc_file_read(cue_handle, buffer, sizeof(buffer) - 1);
if (num_read == 0)
break;
buffer[num_read] = 0;
if (num_read == sizeof(buffer) - 1)
end = buffer + sizeof(buffer) * 3 / 4;
else
end = buffer + num_read;
for (ptr = buffer; ptr < end; ++ptr)
{
while (*ptr == ' ')
++ptr;
if (strncasecmp(ptr, "INDEX ", 6) == 0)
{
int m = 0, s = 0, f = 0;
int index;
int sector_offset;
ptr += 6;
index = atoi(ptr);
while (*ptr != ' ' && *ptr != '\n')
++ptr;
while (*ptr == ' ')
++ptr;
/* convert mm:ss:ff to sector count */
sscanf(ptr, "%d:%d:%d", &m, &s, &f);
sector_offset = ((m * 60) + s) * 75 + f;
if (current_track.first_sector == -1)
{
current_track.first_sector = sector_offset;
if (strcmp(current_track.filename, previous_track.filename) == 0)
{
previous_track.sector_count = current_track.first_sector - previous_track.first_sector;
current_track.file_track_offset += previous_track.sector_count * previous_track.sector_size;
}
/* if looking for the largest data track, determine previous track size */
if (track == RC_HASH_CDTRACK_LARGEST && previous_track.sector_count > largest_track.sector_count &&
previous_track.is_data)
{
memcpy(&largest_track, &previous_track, sizeof(largest_track));
}
}
if (index == 1)
{
current_track.pregap_sectors = (sector_offset - current_track.first_sector);
if (verbose_message_callback)
{
char message[128];
char* scan = current_track.mode;
while (*scan && !isspace((unsigned char)*scan))
++scan;
*scan = '\0';
/* it's undesirable to truncate offset to 32-bits, but %lld isn't defined in c89. */
snprintf(message, sizeof(message), "Found %s track %d (first sector %d, sector size %d, %d pregap sectors)",
current_track.mode, current_track.id, current_track.first_sector, current_track.sector_size, current_track.pregap_sectors);
verbose_message_callback(message);
}
if (current_track.id == track)
{
done = 1;
break;
}
if (track == RC_HASH_CDTRACK_FIRST_DATA && current_track.is_data)
{
track = current_track.id;
done = 1;
break;
}
}
}
else if (strncasecmp(ptr, "TRACK ", 6) == 0)
{
if (current_track.sector_size)
memcpy(&previous_track, &current_track, sizeof(current_track));
ptr += 6;
current_track.id = atoi(ptr);
current_track.pregap_sectors = -1;
current_track.first_sector = -1;
while (*ptr != ' ')
++ptr;
while (*ptr == ' ')
++ptr;
memcpy(current_track.mode, ptr, sizeof(current_track.mode));
current_track.is_data = (memcmp(current_track.mode, "MODE", 4) == 0);
if (current_track.is_data)
{
current_track.sector_size = atoi(ptr + 6);
}
else
{
/* assume AUDIO */
current_track.sector_size = 2352;
}
}
else if (strncasecmp(ptr, "FILE ", 5) == 0)
{
if (current_track.sector_size)
{
memcpy(&previous_track, &current_track, sizeof(previous_track));
if (previous_track.sector_count == 0)
{
const uint32_t file_sector_count = (uint32_t)cdreader_get_bin_size(path, previous_track.filename) / previous_track.sector_size;
previous_track.sector_count = file_sector_count - previous_track.first_sector;
}
/* if looking for the largest data track, check to see if this one is larger */
if (track == RC_HASH_CDTRACK_LARGEST && previous_track.is_data &&
previous_track.sector_count > largest_track.sector_count)
{
memcpy(&largest_track, &previous_track, sizeof(largest_track));
}
}
memset(&current_track, 0, sizeof(current_track));
current_track.file_first_sector = previous_track.file_first_sector +
previous_track.first_sector + previous_track.sector_count;
ptr += 5;
ptr2 = ptr;
if (*ptr == '"')
{
++ptr;
do
{
++ptr2;
} while (*ptr2 && *ptr2 != '\n' && *ptr2 != '"');
}
else
{
do
{
++ptr2;
} while (*ptr2 && *ptr2 != '\n' && *ptr2 != ' ');
}
if (ptr2 - ptr < (int)sizeof(current_track.filename))
memcpy(current_track.filename, ptr, ptr2 - ptr);
}
while (*ptr && *ptr != '\n')
++ptr;
}
if (done)
break;
cue_offset += (ptr - buffer);
rc_file_seek(cue_handle, cue_offset, SEEK_SET);
} while (1);
rc_file_close(cue_handle);
if (track == RC_HASH_CDTRACK_LARGEST)
{
if (current_track.sector_size && current_track.is_data)
{
const uint32_t file_sector_count = (uint32_t)cdreader_get_bin_size(path, current_track.filename) / current_track.sector_size;
current_track.sector_count = file_sector_count - current_track.first_sector;
if (largest_track.sector_count > current_track.sector_count)
memcpy(&current_track, &largest_track, sizeof(current_track));
}
else
{
memcpy(&current_track, &largest_track, sizeof(current_track));
}
track = current_track.id;
}
else if (track == RC_HASH_CDTRACK_LAST && !done)
{
track = current_track.id;
}
if (current_track.id == track)
{
cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom));
if (!cdrom)
{
snprintf((char*)buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)sizeof(*cdrom));
rc_hash_error((const char*)buffer);
return NULL;
}
cdrom->file_track_offset = current_track.file_track_offset;
cdrom->track_pregap_sectors = current_track.pregap_sectors;
cdrom->track_first_sector = current_track.file_first_sector + current_track.first_sector;
#ifndef NDEBUG
cdrom->track_id = current_track.id;
#endif
/* verify existance of bin file */
bin_filename = cdreader_get_bin_path(path, current_track.filename);
if (bin_filename)
{
if (cdreader_open_bin(cdrom, bin_filename, current_track.mode))
{
if (verbose_message_callback)
{
if (cdrom->track_pregap_sectors)
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d, %d pregap sectors)",
track, cdrom->sector_size, cdrom->track_pregap_sectors);
else
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d)", track, cdrom->sector_size);
verbose_message_callback((const char*)buffer);
}
}
else
{
if (cdrom->file_handle)
{
rc_file_close(cdrom->file_handle);
snprintf((char*)buffer, sizeof(buffer), "Could not determine sector size for %s track", current_track.mode);
}
else
{
snprintf((char*)buffer, sizeof(buffer), "Could not open %s", bin_filename);
}
rc_hash_error((const char*)buffer);
free(cdrom);
cdrom = NULL;
}
free(bin_filename);
}
}
return cdrom;
}
static void* cdreader_open_gdi_track(const char* path, uint32_t track)
{
void* file_handle;
char buffer[1024];
char mode[16] = "MODE1/";
char sector_size[16];
char file[256];
int64_t track_size;
int track_type;
char* bin_path = "";
uint32_t current_track = 0;
char* ptr, *ptr2, *end;
int lba = 0;
uint32_t largest_track = 0;
int64_t largest_track_size = 0;
char largest_track_file[256];
char largest_track_sector_size[16];
int largest_track_lba = 0;
int found = 0;
size_t num_read = 0;
int64_t file_offset = 0;
struct cdrom_t* cdrom = NULL;
file_handle = rc_file_open(path);
if (!file_handle)
return NULL;
file[0] = '\0';
do
{
num_read = rc_file_read(file_handle, buffer, sizeof(buffer) - 1);
if (num_read == 0)
break;
buffer[num_read] = 0;
if (num_read == sizeof(buffer) - 1)
end = buffer + sizeof(buffer) * 3 / 4;
else
end = buffer + num_read;
ptr = buffer;
/* the first line contains the number of tracks, so we can get the last track index from it */
if (track == RC_HASH_CDTRACK_LAST)
track = atoi(ptr);
/* first line contains the number of tracks and will be skipped */
while (ptr < end)
{
/* skip until next newline */
while (*ptr != '\n' && ptr < end)
++ptr;
/* skip newlines */
while ((*ptr == '\n' || *ptr == '\r') && ptr < end)
++ptr;
/* line format: [trackid] [lba] [type] [sectorsize] [file] [?] */
while (isspace((unsigned char)*ptr))
++ptr;
current_track = (uint32_t)atoi(ptr);
if (track && current_track != track && track != RC_HASH_CDTRACK_FIRST_DATA)
continue;
while (isdigit((unsigned char)*ptr))
++ptr;
++ptr;
while (isspace((unsigned char)*ptr))
++ptr;
lba = atoi(ptr);
while (isdigit((unsigned char)*ptr))
++ptr;
++ptr;
while (isspace((unsigned char)*ptr))
++ptr;
track_type = atoi(ptr);
while (isdigit((unsigned char)*ptr))
++ptr;
++ptr;
while (isspace((unsigned char)*ptr))
++ptr;
ptr2 = sector_size;
while (isdigit((unsigned char)*ptr))
*ptr2++ = *ptr++;
*ptr2 = '\0';
++ptr;
while (isspace((unsigned char)*ptr))
++ptr;
ptr2 = file;
if (*ptr == '\"')
{
++ptr;
while (*ptr != '\"')
*ptr2++ = *ptr++;
++ptr;
}
else
{
while (*ptr != ' ')
*ptr2++ = *ptr++;
}
*ptr2 = '\0';
if (track == current_track)
{
found = 1;
break;
}
else if (track == RC_HASH_CDTRACK_FIRST_DATA && track_type == 4)
{
track = current_track;
found = 1;
break;
}
else if (track == RC_HASH_CDTRACK_LARGEST && track_type == 4)
{
track_size = cdreader_get_bin_size(path, file);
if (track_size > largest_track_size)
{
largest_track_size = track_size;
largest_track = current_track;
largest_track_lba = lba;
strcpy(largest_track_file, file);
strcpy(largest_track_sector_size, sector_size);
}
}
}
if (found)
break;
file_offset += (ptr - buffer);
rc_file_seek(file_handle, file_offset, SEEK_SET);
} while (1);
rc_file_close(file_handle);
cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom));
if (!cdrom)
{
snprintf((char*)buffer, sizeof(buffer), "Failed to allocate %u bytes", (unsigned)sizeof(*cdrom));
rc_hash_error((const char*)buffer);
return NULL;
}
/* if we were tracking the largest track, make it the current track.
* otherwise, current_track will be the requested track, or last track. */
if (largest_track != 0 && largest_track != current_track)
{
current_track = largest_track;
strcpy(file, largest_track_file);
strcpy(sector_size, largest_track_sector_size);
lba = largest_track_lba;
}
/* open the bin file for the track - construct mode parameter from sector_size */
ptr = &mode[6];
ptr2 = sector_size;
while (*ptr2 && *ptr2 != '\"')
*ptr++ = *ptr2++;
*ptr = '\0';
bin_path = cdreader_get_bin_path(path, file);
if (cdreader_open_bin(cdrom, bin_path, mode))
{
cdrom->track_pregap_sectors = 0;
cdrom->track_first_sector = lba;
#ifndef NDEBUG
cdrom->track_id = current_track;
#endif
if (verbose_message_callback)
{
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d)", current_track, cdrom->sector_size);
verbose_message_callback((const char*)buffer);
}
}
else
{
snprintf((char*)buffer, sizeof(buffer), "Could not open %s", bin_path);
rc_hash_error((const char*)buffer);
free(cdrom);
cdrom = NULL;
}
free(bin_path);
return cdrom;
}
static void* cdreader_open_track(const char* path, uint32_t track)
{
/* backwards compatibility - 0 used to mean largest */
if (track == 0)
track = RC_HASH_CDTRACK_LARGEST;
if (rc_path_compare_extension(path, "cue"))
return cdreader_open_cue_track(path, track);
if (rc_path_compare_extension(path, "gdi"))
return cdreader_open_gdi_track(path, track);
return cdreader_open_bin_track(path, track);
}
static size_t cdreader_read_sector(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes)
{
int64_t sector_start;
size_t num_read, total_read = 0;
uint8_t* buffer_ptr = (uint8_t*)buffer;
struct cdrom_t* cdrom = (struct cdrom_t*)track_handle;
if (!cdrom)
return 0;
if (sector < (uint32_t)cdrom->track_first_sector)
return 0;
sector_start = (int64_t)(sector - cdrom->track_first_sector) * cdrom->sector_size +
cdrom->sector_header_size + cdrom->file_track_offset;
while (requested_bytes > 2048)
{
rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET);
num_read = rc_file_read(cdrom->file_handle, buffer_ptr, 2048);
total_read += num_read;
if (num_read < 2048)
return total_read;
buffer_ptr += 2048;
sector_start += cdrom->sector_size;
requested_bytes -= 2048;
}
rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET);
num_read = rc_file_read(cdrom->file_handle, buffer_ptr, (int)requested_bytes);
total_read += num_read;
return total_read;
}
static void cdreader_close_track(void* track_handle)
{
struct cdrom_t* cdrom = (struct cdrom_t*)track_handle;
if (cdrom)
{
if (cdrom->file_handle)
rc_file_close(cdrom->file_handle);
free(track_handle);
}
}
static uint32_t cdreader_first_track_sector(void* track_handle)
{
struct cdrom_t* cdrom = (struct cdrom_t*)track_handle;
if (cdrom)
return cdrom->track_first_sector + cdrom->track_pregap_sectors;
return 0;
}
void rc_hash_get_default_cdreader(struct rc_hash_cdreader* cdreader)
{
cdreader->open_track = cdreader_open_track;
cdreader->read_sector = cdreader_read_sector;
cdreader->close_track = cdreader_close_track;
cdreader->first_track_sector = cdreader_first_track_sector;
}
void rc_hash_init_default_cdreader()
{
struct rc_hash_cdreader cdreader;
rc_hash_get_default_cdreader(&cdreader);
rc_hash_init_custom_cdreader(&cdreader);
}
+131 -62
View File
@@ -83,6 +83,12 @@ static void filereader_close(void* file_handle)
fclose((FILE*)file_handle);
}
/* for unit tests - normally would call rc_hash_init_custom_filereader(NULL) */
void rc_hash_reset_filereader(void)
{
filereader = NULL;
}
void rc_hash_init_custom_filereader(struct rc_hash_filereader* reader)
{
/* initialize with defaults first */
@@ -193,13 +199,13 @@ static size_t rc_cd_read_sector(void* track_handle, uint32_t sector, void* buffe
return 0;
}
static uint32_t rc_cd_absolute_sector_to_track_sector(void* track_handle, uint32_t sector)
static uint32_t rc_cd_first_track_sector(void* track_handle)
{
if (cdreader && cdreader->absolute_sector_to_track_sector)
return cdreader->absolute_sector_to_track_sector(track_handle, sector);
if (cdreader && cdreader->first_track_sector)
return cdreader->first_track_sector(track_handle);
rc_hash_error("no hook registered for cdreader_absolute_sector_to_track_sector");
return sector;
rc_hash_error("no hook registered for cdreader_first_track_sector");
return 0;
}
static void rc_cd_close_track(void* track_handle)
@@ -242,7 +248,7 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
else
{
/* find the cd information */
if (!rc_cd_read_sector(track_handle, 16, buffer, 256))
if (!rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle) + 16, buffer, 256))
return 0;
/* the directory_record starts at 156, the sector containing the table of contents is 2 bytes into that.
@@ -252,7 +258,6 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
}
/* fetch and process the directory record */
sector = rc_cd_absolute_sector_to_track_sector(track_handle, sector);
if (!rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer)))
return 0;
@@ -405,7 +410,7 @@ static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector
if (name)
snprintf(message, sizeof(message), "Hashing %s title (%u bytes) and contents (%u bytes) ", name, (unsigned)strlen(name), size);
else
snprintf(message, sizeof(message), "Hashing %s contents (%u bytes)", description, size);
snprintf(message, sizeof(message), "Hashing %s contents (%u bytes @ sector %u)", description, size, sector);
verbose_message_callback(message);
}
@@ -648,6 +653,37 @@ static int rc_hash_arcade(char hash[33], const char* path)
return rc_hash_buffer(hash, (uint8_t*)filename, filename_length);
}
static int rc_hash_text(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
md5_state_t md5;
const uint8_t* scan = buffer;
const uint8_t* stop = buffer + buffer_size;
md5_init(&md5);
do {
/* find end of line */
while (scan < stop && *scan != '\r' && *scan != '\n')
++scan;
md5_append(&md5, buffer, (int)(scan - buffer));
/* include a normalized line ending */
/* NOTE: this causes a line ending to be hashed at the end of the file, even if one was not present */
md5_append(&md5, (const uint8_t*)"\n", 1);
/* skip newline */
if (scan < stop && *scan == '\r')
++scan;
if (scan < stop && *scan == '\n')
++scan;
buffer = scan;
} while (scan < stop);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_lynx(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
@@ -947,7 +983,7 @@ static int rc_hash_pce_track(char hash[33], void* track_handle)
* the string "PC Engine CD-ROM SYSTEM" should exist at 32 bytes into the sector
* http://shu.sheldows.com/shu/download/pcedocs/pce_cdrom.html
*/
if (rc_cd_read_sector(track_handle, 1, buffer, 128) < 128)
if (rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle) + 1, buffer, 128) < 128)
{
return rc_hash_error("Not a PC Engine CD");
}
@@ -980,6 +1016,7 @@ static int rc_hash_pce_track(char hash[33], void* track_handle)
verbose_message_callback(message);
}
sector += rc_cd_first_track_sector(track_handle);
while (num_sectors > 0)
{
rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
@@ -1043,7 +1080,8 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
return rc_hash_error("Could not open track");
/* PC-FX CD will have a header marker in sector 0 */
rc_cd_read_sector(track_handle, 0, buffer, 32);
sector = rc_cd_first_track_sector(track_handle);
rc_cd_read_sector(track_handle, sector, buffer, 32);
if (memcmp("PC-FX:Hu_CD-ROM", &buffer[0], 15) != 0)
{
rc_cd_close_track(track_handle);
@@ -1053,7 +1091,8 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
if (!track_handle)
return rc_hash_error("Could not open track");
rc_cd_read_sector(track_handle, 0, buffer, 32);
sector = rc_cd_first_track_sector(track_handle);
rc_cd_read_sector(track_handle, sector, buffer, 32);
}
if (memcmp("PC-FX:Hu_CD-ROM", &buffer[0], 15) == 0)
@@ -1061,7 +1100,7 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
/* PC-FX boot header fills the first two sectors of the disc
* https://bitbucket.org/trap15/pcfxtools/src/master/pcfx-cdlink.c
* the important stuff is the first 128 bytes of the second sector (title being the first 32) */
rc_cd_read_sector(track_handle, 1, buffer, 128);
rc_cd_read_sector(track_handle, sector + 1, buffer, 128);
md5_init(&md5);
md5_append(&md5, buffer, 128);
@@ -1087,6 +1126,7 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
verbose_message_callback(message);
}
sector += rc_cd_first_track_sector(track_handle);
while (num_sectors > 0)
{
rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
@@ -1099,7 +1139,7 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
else
{
int result = 0;
rc_cd_read_sector(track_handle, 1, buffer, 128);
rc_cd_read_sector(track_handle, sector + 1, buffer, 128);
/* some PC-FX CDs still identify as PCE CDs */
if (memcmp("PC Engine CD-ROM SYSTEM", &buffer[32], 23) == 0)
@@ -1119,30 +1159,41 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
static int rc_hash_dreamcast(char hash[33], const char* path)
{
uint8_t buffer[256];
uint8_t buffer[256] = "";
void* track_handle;
void* last_track_handle;
char exe_file[32] = "";
unsigned size;
uint32_t sector;
uint32_t track_sector;
int result = 0;
md5_state_t md5;
int i = 0;
/* track 03 is the data track that contains the TOC and IP.BIN */
track_handle = rc_cd_open_track(path, 3);
if (!track_handle)
return rc_hash_error("Could not open track");
/* first 256 bytes from first sector should have IP.BIN structure that stores game meta information
* https://mc.pp.se/dc/ip.bin.html */
rc_cd_read_sector(track_handle, 0, buffer, sizeof(buffer));
if (track_handle)
{
/* first 256 bytes from first sector should have IP.BIN structure that stores game meta information
* https://mc.pp.se/dc/ip.bin.html */
rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle), buffer, sizeof(buffer));
}
if (memcmp(&buffer[0], "SEGA SEGAKATANA ", 16) != 0)
{
rc_cd_close_track(track_handle);
return rc_hash_error("Not a Dreamcast CD");
if (track_handle)
rc_cd_close_track(track_handle);
/* not a gd-rom dreamcast file. check for mil-cd by looking for the marker in the first data track */
track_handle = rc_cd_open_track(path, RC_HASH_CDTRACK_FIRST_DATA);
if (!track_handle)
return rc_hash_error("Could not open track");
rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle), buffer, sizeof(buffer));
if (memcmp(&buffer[0], "SEGA SEGAKATANA ", 16) != 0)
{
/* did not find marker on track 3 or first data track */
rc_cd_close_track(track_handle);
return rc_hash_error("Not a Dreamcast CD");
}
}
/* start the hash with the game meta information */
@@ -1179,30 +1230,26 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
exe_file[i] = '\0';
sector = rc_cd_find_file_sector(track_handle, exe_file, &size);
rc_cd_close_track(track_handle);
if (sector == 0)
return rc_hash_error("Could not locate boot executable");
/* last track contains the boot executable */
last_track_handle = rc_cd_open_track(path, RC_HASH_CDTRACK_LAST);
track_sector = rc_cd_absolute_sector_to_track_sector(last_track_handle, sector);
if ((int32_t)track_sector < 0)
{
/* boot executable is not in the last track; try the primary data track.
* There's only a handful of games that do this: Q*bert was the first identified. */
rc_cd_close_track(last_track_handle);
rc_hash_verbose("Boot executable not found in last track, trying primary track");
last_track_handle = rc_cd_open_track(path, 3);
track_sector = rc_cd_absolute_sector_to_track_sector(last_track_handle, sector);
rc_cd_close_track(track_handle);
return rc_hash_error("Could not locate boot executable");
}
result = rc_hash_cd_file(&md5, last_track_handle, track_sector, NULL, size, "boot executable");
if (rc_cd_read_sector(track_handle, sector, buffer, 1))
{
/* the boot executable is in the primary data track */
}
else
{
rc_cd_close_track(track_handle);
rc_cd_close_track(last_track_handle);
/* the boot executable is normally in the last track */
track_handle = rc_cd_open_track(path, RC_HASH_CDTRACK_LAST);
}
result = rc_hash_cd_file(&md5, track_handle, sector, NULL, size, "boot executable");
rc_cd_close_track(track_handle);
rc_hash_finalize(&md5, hash);
return result;
@@ -1525,23 +1572,24 @@ void rc_file_close_buffered_file(void* file_handle)
static int rc_hash_file_from_buffer(char hash[33], int console_id, const uint8_t* buffer, size_t buffer_size)
{
struct rc_hash_filereader filereader_funcs_old;
struct rc_hash_filereader buffered_filereader_funcs;
struct rc_hash_filereader* old_filereader = filereader;
int result;
memcpy(&filereader_funcs_old, &filereader_funcs, sizeof(filereader_funcs));
filereader_funcs.open = rc_file_open_buffered_file;
filereader_funcs.close = rc_file_close_buffered_file;
filereader_funcs.read = rc_file_read_buffered_file;
filereader_funcs.seek = rc_file_seek_buffered_file;
filereader_funcs.tell = rc_file_tell_buffered_file;
memset(&buffered_filereader_funcs, 0, sizeof(buffered_filereader_funcs));
buffered_filereader_funcs.open = rc_file_open_buffered_file;
buffered_filereader_funcs.close = rc_file_close_buffered_file;
buffered_filereader_funcs.read = rc_file_read_buffered_file;
buffered_filereader_funcs.seek = rc_file_seek_buffered_file;
buffered_filereader_funcs.tell = rc_file_tell_buffered_file;
filereader = &buffered_filereader_funcs;
rc_buffered_file.data = rc_buffered_file.read_ptr = buffer;
rc_buffered_file.data_size = buffer_size;
result = rc_hash_generate_from_file(hash, console_id, "[buffered file]");
memcpy(&filereader_funcs, &filereader_funcs_old, sizeof(filereader_funcs));
filereader = old_filereader;
return result;
}
@@ -1556,6 +1604,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
return rc_hash_error(message);
}
case RC_CONSOLE_AMSTRAD_PC:
case RC_CONSOLE_APPLE_II:
case RC_CONSOLE_ATARI_2600:
case RC_CONSOLE_ATARI_JAGUAR:
@@ -1568,6 +1617,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
case RC_CONSOLE_MAGNAVOX_ODYSSEY2:
case RC_CONSOLE_MASTER_SYSTEM:
case RC_CONSOLE_MEGA_DRIVE:
case RC_CONSOLE_MEGADUCK:
case RC_CONSOLE_MSX:
case RC_CONSOLE_NEOGEO_POCKET:
case RC_CONSOLE_ORIC:
@@ -1582,6 +1632,10 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
case RC_CONSOLE_WONDERSWAN:
return rc_hash_buffer(hash, buffer, buffer_size);
case RC_CONSOLE_ARDUBOY:
/* https://en.wikipedia.org/wiki/Intel_HEX */
return rc_hash_text(hash, buffer, buffer_size);
case RC_CONSOLE_ATARI_7800:
return rc_hash_7800(hash, buffer, buffer_size);
@@ -1841,7 +1895,6 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
return rc_hash_error(buffer);
}
case RC_CONSOLE_APPLE_II:
case RC_CONSOLE_ATARI_2600:
case RC_CONSOLE_ATARI_JAGUAR:
case RC_CONSOLE_COLECOVISION:
@@ -1853,6 +1906,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_MAGNAVOX_ODYSSEY2:
case RC_CONSOLE_MASTER_SYSTEM:
case RC_CONSOLE_MEGA_DRIVE:
case RC_CONSOLE_MEGADUCK:
case RC_CONSOLE_NEOGEO_POCKET:
case RC_CONSOLE_ORIC:
case RC_CONSOLE_POKEMON_MINI:
@@ -1866,6 +1920,8 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
/* generic whole-file hash - don't buffer */
return rc_hash_whole_file(hash, path);
case RC_CONSOLE_AMSTRAD_PC:
case RC_CONSOLE_APPLE_II:
case RC_CONSOLE_MSX:
case RC_CONSOLE_PC8800:
/* generic whole-file hash with m3u support - don't buffer */
@@ -1874,6 +1930,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
return rc_hash_whole_file(hash, path);
case RC_CONSOLE_ARDUBOY:
case RC_CONSOLE_ATARI_7800:
case RC_CONSOLE_ATARI_LYNX:
case RC_CONSOLE_NINTENDO:
@@ -1985,6 +2042,9 @@ static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, c
{
/* FAT-12 5.25" DD (512 byte sectors, 9 sectors per track, 40 tracks per side */
iterator->consoles[0] = RC_CONSOLE_MSX;
/* AMSDOS 3" - 40 tracks */
iterator->consoles[1] = RC_CONSOLE_AMSTRAD_PC;
}
else if (size == 256 * 16 * 35) /* 140KB */
{
@@ -2001,6 +2061,7 @@ static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, c
/* check MSX first, as Apple II isn't supported by RetroArch, and RAppleWin won't use the iterator */
rc_hash_iterator_append_console(iterator, RC_CONSOLE_MSX);
rc_hash_iterator_append_console(iterator, RC_CONSOLE_AMSTRAD_PC);
rc_hash_iterator_append_console(iterator, RC_CONSOLE_APPLE_II);
}
@@ -2071,7 +2132,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
}
/* bin is associated with MegaDrive, Sega32X, Atari 2600, and Watara Supervision.
/* bin is associated with MegaDrive, Sega32X, Atari 2600, Watara Supervision, and MegaDuck.
* Since they all use the same hashing algorithm, only specify one of them */
iterator->consoles[0] = RC_CONSOLE_MEGA_DRIVE;
}
@@ -2086,10 +2147,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION;
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
iterator->consoles[2] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[3] = RC_CONSOLE_3DO;
iterator->consoles[4] = RC_CONSOLE_PCFX;
iterator->consoles[5] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[5] = RC_CONSOLE_3DO;
iterator->consoles[6] = RC_CONSOLE_PCFX;
need_path = 1;
}
else if (rc_path_compare_extension(ext, "chd"))
@@ -2097,10 +2159,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION;
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
iterator->consoles[3] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[4] = RC_CONSOLE_3DO;
iterator->consoles[5] = RC_CONSOLE_PCFX;
iterator->consoles[6] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[5] = RC_CONSOLE_3DO;
iterator->consoles[6] = RC_CONSOLE_PCFX;
need_path = 1;
}
else if (rc_path_compare_extension(ext, "col"))
@@ -2163,6 +2225,13 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
break;
case 'h':
if (rc_path_compare_extension(ext, "hex"))
{
iterator->consoles[0] = RC_CONSOLE_ARDUBOY;
}
break;
case 'i':
if (rc_path_compare_extension(ext, "iso"))
{
+22
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2019-2020 - James Leaver
* Copyright (C) 2022-2022 - Jahed Ahmed
*
* RetroArch 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 Found-
@@ -49,6 +50,9 @@
#define DINGUX_SCALING_SHARPNESS_ENVAR "SDL_VIDEO_KMSDRM_SCALING_SHARPNESS"
#define DINGUX_VIDEO_REFRESHRATE_ENVAR "SDL_VIDEO_REFRESHRATE"
/* Miyoo defines */
#define MIYOO_BATTERY_VOLTAGE_NOW_FILE "/sys/class/power_supply/miyoo-battery/voltage_now"
/* Enables/disables downscaling when using
* the IPU hardware scaler */
bool dingux_ipu_set_downscaling_enable(bool enable)
@@ -307,6 +311,24 @@ int dingux_get_battery_level(void)
return -1;
return (int)(((voltage_now - voltage_min) * 100) / (voltage_max - voltage_min));
#elif defined(MIYOO)
/* miyoo-battery only provides "voltage_now". Results are based on
* value distribution while running a game at max load. */
int voltage_now = dingux_read_battery_sys_file(MIYOO_BATTERY_VOLTAGE_NOW_FILE);
if (voltage_now < 0) return -1; // voltage_now not available
if (voltage_now > 4300) return 100; // 4320
if (voltage_now > 4200) return 90; // 4230
if (voltage_now > 4100) return 80; // 4140
if (voltage_now > 4000) return 70; // 4050
if (voltage_now > 3900) return 60; // 3960
if (voltage_now > 3800) return 50; // 3870
if (voltage_now > 3700) return 40; // 3780
if (voltage_now > 3600) return 30; // 3690
if (voltage_now > 3550) return 20; // 3600
if (voltage_now > 3500) return 10; // 3510
if (voltage_now > 3400) return 5; // 3420
if (voltage_now > 3300) return 1; // 3330
return 0; // 3240
#else
return dingux_read_battery_sys_file(DINGUX_BATTERY_CAPACITY_FILE);
#endif
+14 -11
View File
@@ -627,6 +627,7 @@ void drivers_init(
#ifdef HAVE_LIBRETRODB
menu_explore_context_init();
#endif
menu_contentless_cores_context_init();
}
}
@@ -694,6 +695,7 @@ void driver_uninit(int flags)
#ifdef HAVE_LIBRETRODB
menu_explore_context_deinit();
#endif
menu_contentless_cores_context_deinit();
menu_driver_ctl(RARCH_MENU_CTL_DEINIT, NULL);
}
@@ -808,18 +810,19 @@ void retroarch_deinit_drivers(struct retro_callbacks *cbs)
audio_state_get_ptr()->active = false;
audio_state_get_ptr()->current_audio = NULL;
/* Input */
input_st->keyboard_linefeed_enable = false;
input_st->block_hotkey = false;
input_st->block_libretro_input = false;
if (input_st)
input_st->nonblocking_flag = false;
memset(&input_st->turbo_btns, 0, sizeof(turbo_buttons_t));
memset(&input_st->analog_requested, 0,
if (input_st)
{
/* Input */
input_st->keyboard_linefeed_enable = false;
input_st->block_hotkey = false;
input_st->block_libretro_input = false;
input_st->nonblocking_flag = false;
memset(&input_st->turbo_btns, 0, sizeof(turbo_buttons_t));
memset(&input_st->analog_requested, 0,
sizeof(input_st->analog_requested));
input_st->current_driver = NULL;
input_st->current_driver = NULL;
}
#ifdef HAVE_MENU
menu_driver_destroy(
+2
View File
@@ -107,6 +107,8 @@ RETRO_BEGIN_DECLS
#define FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT "lcbk"
#define FILE_PATH_LOCK_EXTENSION ".lck"
#define FILE_PATH_LOCK_EXTENSION_NO_DOT "lck"
#define FILE_PATH_STANDALONE_EXEMPT_EXTENSION ".lsae"
#define FILE_PATH_STANDALONE_EXEMPT_EXTENSION_NO_DOT "lsae"
#define FILE_PATH_BACKUP_EXTENSION ".bak"
#if defined(RARCH_MOBILE)
#define FILE_PATH_DEFAULT_OVERLAY "gamepads/neo-retropad/neo-retropad.cfg"
+14 -13
View File
@@ -114,7 +114,7 @@ typedef enum
CFAllDomainsMask = 0x0ffff /* All domains: all of the above and future items */
} CFDomainMask;
#if (defined(OSX) && !(defined(__ppc__) || defined(__ppc64__)))
#if (defined(OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
static int speak_pid = 0;
#endif
@@ -128,14 +128,19 @@ static void CFSearchPathForDirectoriesInDomains(
#else
NSSearchPathDirectory dir = NSDocumentDirectory;
#endif
CFStringRef array_val;
#if __has_feature(objc_arc)
CFStringRef array_val = (__bridge CFStringRef)[
array_val = (__bridge CFStringRef)[
NSSearchPathForDirectoriesInDomains(dir,
NSUserDomainMask, YES) firstObject];
#else
CFStringRef array_val = (CFStringRef)[
NSSearchPathForDirectoriesInDomains(dir,
NSUserDomainMask, YES) firstObject];
NSArray *arr = NSSearchPathForDirectoriesInDomains(dir,
NSUserDomainMask, YES);
if ([arr count] == 0) {
array_val = nil;
} else{
array_val = (CFStringRef)[arr objectAtIndex:0];
}
#endif
if (array_val)
CFStringGetCString(array_val, s, len, kCFStringEncodingUTF8);
@@ -805,7 +810,7 @@ static uint64_t frontend_darwin_get_total_mem(void)
static uint64_t frontend_darwin_get_free_mem(void)
{
#if (defined(OSX) && !(defined(__ppc__) || defined(__ppc64__)))
#if (defined(OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
vm_size_t page_size;
vm_statistics64_data_t vm_stats;
mach_port_t mach_port = mach_host_self();
@@ -831,7 +836,7 @@ static const char* frontend_darwin_get_cpu_model_name(void)
return darwin_cpu_model_name;
}
#if (defined(OSX) && !(defined(__ppc__) || defined(__ppc64__)))
#if (defined(OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
static char* accessibility_mac_language_code(const char* language)
{
if (string_is_equal(language,"en"))
@@ -995,13 +1000,9 @@ frontend_ctx_driver_t frontend_ctx_darwin = {
NULL, /* watch_path_for_changes */
NULL, /* check_for_path_changes */
NULL, /* set_sustained_performance_mode */
#if (defined(OSX) && !(defined(__ppc__) || defined(__ppc64__)))
frontend_darwin_get_cpu_model_name, /* get_cpu_model_name */
#else
NULL, /* get_cpu_model_name */
#endif
frontend_darwin_get_cpu_model_name, /* get_cpu_model_name */
NULL, /* get_user_language */
#if (defined(OSX) && !(defined(__ppc__) || defined(__ppc64__)))
#if (defined(OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
is_narrator_running_macos, /* is_narrator_running */
accessibility_speak_macos, /* accessibility_speak */
#else
+5 -4
View File
@@ -23,6 +23,7 @@
#include "../frontend_driver.h"
#include "../../defaults.h"
#include "../../paths.h"
#include "../command.h"
static enum frontend_fork dos_fork_mode = FRONTEND_FORK_NONE;
@@ -145,21 +146,21 @@ static void frontend_dos_exitspawn(char *s, size_t len, char *args)
frontend_dos_exec(s, should_load_content);
}
static bool frontend_unix_set_fork(enum frontend_fork fork_mode)
static bool frontend_dos_set_fork(enum frontend_fork fork_mode)
{
switch (fork_mode)
{
case FRONTEND_FORK_CORE:
RARCH_LOG("FRONTEND_FORK_CORE\n");
unix_fork_mode = fork_mode;
dos_fork_mode = fork_mode;
break;
case FRONTEND_FORK_CORE_WITH_ARGS:
RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
unix_fork_mode = fork_mode;
dos_fork_mode = fork_mode;
break;
case FRONTEND_FORK_RESTART:
RARCH_LOG("FRONTEND_FORK_RESTART\n");
unix_fork_mode = FRONTEND_FORK_CORE;
dos_fork_mode = FRONTEND_FORK_CORE;
{
char executable_path[PATH_MAX_LENGTH] = {0};
+9 -1
View File
@@ -29,6 +29,11 @@
#include "../../config.h"
#endif
#include <retroarch_types.h>
#include <msg_hash.h>
#include <command.h>
#include <verbosity.h>
#if defined(HW_RVL) && !defined(IS_SALAMANDER)
#include <rthreads/rthreads.h>
#include "../../memory/wii/mem2_manager.h"
@@ -162,6 +167,9 @@ static void frontend_gx_get_env(
{
char *last_slash = NULL;
char *device_end = NULL;
#if defined(HAVE_LOGGER) && !defined(IS_SALAMANDER)
logger_init();
#endif
#ifndef IS_SALAMANDER
/* This situation can happen on some loaders so we really need some
@@ -241,7 +249,7 @@ static void frontend_gx_get_env(
"cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
/* User paths */
fill_pathname_join(g_defaults.path_config, g_defaults.dirs[DEFAULT_DIR_PORT],
fill_pathname_join(g_defaults.path_config, g_defaults.dirs[DEFAULT_DIR_CORE],
"retroarch.cfg", sizeof(g_defaults.path_config));
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_PORT],
"system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
+38
View File
@@ -73,6 +73,18 @@ SYS_PROCESS_PARAM(1001, 0x200000)
static bool multiman_detected = false;
#endif
#ifdef HAVE_MEMINFO
typedef struct {
uint32_t total;
uint32_t avail;
} sys_memory_info_t;
#ifdef __PSL1GHT__
#define sys_memory_get_user_memory_size(x) lv2syscall1(352, x)
#else
#define sys_memory_get_user_memory_size(x) system_call_1(352, x)
#endif
#endif
#ifndef IS_SALAMANDER
static enum frontend_fork ps3_fork_mode = FRONTEND_FORK_NONE;
@@ -365,6 +377,11 @@ static void frontend_ps3_init(void *data)
cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP);
#endif
#ifdef HAVE_LIGHTGUN
cellSysmoduleLoadModule(SYSMODULE_GEM);
cellSysmoduleLoadModule(SYSMODULE_CAMERA);
#endif
#ifndef __PSL1GHT__
sys_net_initialize_network();
sceNpInit(NP_POOL_SIZE, np_pool);
@@ -674,6 +691,22 @@ static void frontend_ps3_process_args(int *argc, char *argv[])
#endif
}
#ifdef HAVE_MEMINFO
static size_t frontend_ps3_get_mem_total(void)
{
sys_memory_info_t mem_info;
sys_memory_get_user_memory_size(&mem_info);
return mem_info.total;
}
static size_t frontend_ps3_get_mem_used(void)
{
sys_memory_info_t mem_info;
sys_memory_get_user_memory_size(&mem_info);
return mem_info.avail;
}
#endif
frontend_ctx_driver_t frontend_ctx_ps3 = {
frontend_ps3_get_env,
frontend_ps3_init,
@@ -694,8 +727,13 @@ frontend_ctx_driver_t frontend_ctx_ps3 = {
frontend_ps3_get_arch, /* get_architecture */
NULL, /* get_powerstate */
frontend_ps3_parse_drive_list,/* parse_drive_list */
#ifdef HAVE_MEMINFO
frontend_ps3_get_mem_total,
frontend_ps3_get_mem_used,
#else
NULL, /* get_total_mem */
NULL, /* get_free_mem */
#endif
NULL, /* install_signal_handler */
NULL, /* get_sighandler_state */
NULL, /* set_sighandler_state */
+5 -15
View File
@@ -60,11 +60,9 @@
#include "../../paths.h"
#include "../../verbosity.h"
#if defined(HAVE_KERNEL_PRX) || defined(IS_SALAMANDER)
#ifndef VITA
#if defined(PSP) && defined(HAVE_KERNEL_PRX)
#include "../../bootstrap/psp1/kernel_functions.h"
#endif
#endif
#if defined(HAVE_VITAGLES)
#include "../../deps/Pigs-In-A-Blanket/include/pib.h"
@@ -73,10 +71,6 @@
#ifndef VITA
PSP_MODULE_INFO("RetroArch", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER|THREAD_ATTR_VFPU);
#ifdef BIG_STACK
PSP_MAIN_THREAD_STACK_SIZE_KB(4*1024);
#endif
PSP_HEAP_SIZE_MAX();
#endif
#ifdef SCE_LIBC_SIZE
@@ -241,7 +235,7 @@ static void frontend_psp_shutdown(bool unused)
//sceKernelExitProcess(0);
return;
#else
sceKernelExitGame();
exit(0);
#endif
}
@@ -309,16 +303,13 @@ static void frontend_psp_init(void *data)
#endif
#if defined(HAVE_KERNEL_PRX) || defined(IS_SALAMANDER)
#ifndef VITA
#if defined(PSP) && defined(HAVE_KERNEL_PRX)
pspSdkLoadStartModule("kernel_functions.prx", PSP_MEMORY_PARTITION_KERNEL);
#endif
#endif
}
static void frontend_psp_exec(const char *path, bool should_load_game)
{
#if defined(HAVE_KERNEL_PRX) || defined(IS_SALAMANDER) || defined(VITA)
#ifdef IS_SALAMANDER
char boot_params[1024];
char core_name[256];
@@ -326,7 +317,7 @@ static void frontend_psp_exec(const char *path, bool should_load_game)
char argp[512] = {0};
SceSize args = 0;
#if !defined(VITA)
#if defined(PSP)
strlcpy(argp, eboot_path, sizeof(argp));
args = strlen(argp) + 1;
#endif
@@ -392,10 +383,9 @@ static void frontend_psp_exec(const char *path, bool should_load_game)
int ret = sceAppMgrLoadExec(path, args == 0 ? NULL : (char * const*)((const char*[]){argp, 0}), NULL);
RARCH_LOG("Attempt to load executable: [%d].\n", ret);
}
#else
#elif defined(PSP) && defined(HAVE_KERNEL_PRX)
exitspawn_kernel(path, args, argp);
#endif
#endif
}
#ifndef IS_SALAMANDER
+67 -9
View File
@@ -1274,12 +1274,7 @@ static enum frontend_architecture frontend_unix_get_arch(void)
string_is_equal(val, "armv7b")
)
return FRONTEND_ARCH_ARMV7;
else if (
string_is_equal(val, "armv6l") ||
string_is_equal(val, "armv6b") ||
string_is_equal(val, "armv5tel") ||
string_is_equal(val, "arm")
)
else if (string_starts_with(val, "arm"))
return FRONTEND_ARCH_ARM;
else if (string_is_equal(val, "x86_64"))
return FRONTEND_ARCH_X86_64;
@@ -1377,6 +1372,7 @@ static void frontend_unix_get_env(int *argc,
char *argv[], void *data, void *params_data)
{
unsigned i;
const char* libretro_directory = getenv("LIBRETRO_DIRECTORY");
#ifdef ANDROID
int32_t major, minor, rel;
char device_model[PROP_VALUE_MAX] = {0};
@@ -1798,7 +1794,7 @@ static void frontend_unix_get_env(int *argc,
char base_path[PATH_MAX] = {0};
#if defined(RARCH_UNIX_CWD_ENV)
/* The entire path is zero initialized. */
base_path[0] = '.';
getcwd(base_path, sizeof(base_path));
#elif defined(DINGUX)
dingux_get_base_path(base_path, sizeof(base_path));
#else
@@ -1819,8 +1815,12 @@ static void frontend_unix_get_env(int *argc,
strcpy_literal(base_path, "retroarch");
#endif
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
"cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
if (!string_is_empty(libretro_directory))
strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE], libretro_directory,
sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
else
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
"cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
#if defined(DINGUX)
/* On platforms that require manual core installation/
* removal, placing core info files in the same directory
@@ -2135,6 +2135,10 @@ static void frontend_unix_init(void *data)
"deleteCore", "(Ljava/lang/String;)V");
CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
android_app->getIntent);
GET_METHOD_ID(env, android_app->getVolumeCount, class,
"getVolumeCount", "()I");
GET_METHOD_ID(env, android_app->getVolumePath, class,
"getVolumePath", "(Ljava/lang/String;)Ljava/lang/String;");
GET_OBJECT_CLASS(env, class, obj);
GET_METHOD_ID(env, android_app->getStringExtra, class,
@@ -2152,6 +2156,29 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content)
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
#ifdef ANDROID
JNIEnv *env = jni_thread_getenv();
jint output = 0;
jobject obj = NULL;
jstring jstr = NULL;
int volume_count = 0;
if (!env || !g_android)
return 0;
CALL_OBJ_METHOD(env, obj, g_android->activity->clazz,
g_android->getIntent);
if (g_android->getVolumeCount)
{
CALL_INT_METHOD(env, output,
g_android->activity->clazz, g_android->getVolumeCount);
volume_count = output;
}
RARCH_LOG("external volumes: %d\n", volume_count);
if (!string_is_empty(internal_storage_path))
{
if (storage_permissions == INTERNAL_STORAGE_WRITABLE)
@@ -2198,6 +2225,37 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content)
msg_hash_to_str(MSG_APPLICATION_DIR),
enum_idx,
FILE_TYPE_DIRECTORY, 0, 0);
for (unsigned i=0; i < volume_count; i++)
{
static char aux_path[PATH_MAX_LENGTH];
char index[2];
index[0] = '\0';
snprintf(index, sizeof(index), "%d", i);
CALL_OBJ_METHOD_PARAM(env, jstr, g_android->activity->clazz, g_android->getVolumePath,
(*env)->NewStringUTF(env, index));
if (jstr)
{
const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
aux_path[0] = '\0';
if (str && *str)
strlcpy(aux_path, str,
sizeof(aux_path));
(*env)->ReleaseStringUTFChars(env, jstr, str);
if (!string_is_empty(aux_path))
menu_entries_append_enum(list,
aux_path,
msg_hash_to_str(MSG_APPLICATION_DIR),
enum_idx,
FILE_TYPE_DIRECTORY, 0, 0);
}
}
#elif defined(WEBOS)
if (path_is_directory("/media/internal"))
menu_entries_append_enum(list, "/media/internal",
+3
View File
@@ -175,6 +175,9 @@ struct android_app
jmethodID downloadCore;
jmethodID deleteCore;
jmethodID getVolumeCount;
jmethodID getVolumePath;
struct
{
unsigned width, height;
+1
View File
@@ -29,6 +29,7 @@
#include <file/file_path.h>
#include <retro_miscellaneous.h>
#include <paths.h>
#ifdef HAVE_CONFIG_H
#include "../../config.h"
+7 -2
View File
@@ -571,6 +571,7 @@ static void frontend_win32_env_get(int *argc, char *argv[],
void *args, void *params_data)
{
const char *tmp_dir = getenv("TMP");
const char *libretro_directory = getenv("LIBRETRO_DIRECTORY");
if (!string_is_empty(tmp_dir))
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CACHE],
tmp_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE]));
@@ -609,8 +610,12 @@ static void frontend_win32_env_get(int *argc, char *argv[],
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT],
":\\layouts", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT]));
#endif
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE],
":\\cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
if (!string_is_empty(libretro_directory))
strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE], libretro_directory,
sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
else
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE],
":\\cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_CORE_INFO],
":\\info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
+1 -1
View File
@@ -251,7 +251,7 @@ bool frontend_driver_get_salamander_basename(char *s, size_t len)
strcpy_literal(s, "eboot.bin");
return true;
#elif defined(PS2)
strcpy_literal(s, "eboot.elf");
strcpy_literal(s, "raboot.elf");
return true;
#elif defined(__PSL1GHT__) || defined(__PS3__)
strcpy_literal(s, "EBOOT.BIN");
+1
View File
@@ -1152,6 +1152,7 @@ typedef struct
D3D10_VIEWPORT viewport;
DXGI_FORMAT format;
float clearcolor[4];
unsigned swap_interval;
bool vsync;
bool resize_chain;
bool keep_aspect;
+1
View File
@@ -2543,6 +2543,7 @@ typedef struct
D3D11_RECT scissor;
DXGI_FORMAT format;
float clearcolor[4];
unsigned swap_interval;
bool vsync;
bool resize_chain;
bool keep_aspect;
+3 -3
View File
@@ -40,7 +40,7 @@ RETRO_BEGIN_DECLS
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#elif (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
@@ -59,7 +59,7 @@ RETRO_BEGIN_DECLS
#endif
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#elif (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
@@ -76,7 +76,7 @@ RETRO_BEGIN_DECLS
#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
#endif
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
#if (defined(__MACH__) && defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < 101200))
#define RARCH_GL_MAX_RENDERBUFFER_SIZE GL_MAX_RENDERBUFFER_SIZE_EXT
#elif defined(HAVE_PSGL)
#define RARCH_GL_MAX_RENDERBUFFER_SIZE GL_MAX_RENDERBUFFER_SIZE_OES
+149
View File
@@ -0,0 +1,149 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* RetroArch 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 Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RSX_COMMON_H__
#define RSX_COMMON_H__
#include <rsx/rsx.h>
#include <rsx/nv40.h>
#include <ppu-types.h>
#include <retro_inline.h>
#include <string/stdstring.h>
#include <gfx/math/matrix_4x4.h>
#include <defines/ps3_defines.h>
#include "../../driver.h"
#include "../../retroarch.h"
#include "../video_coord_array.h"
#define MAX_BUFFERS 2
#define MAX_MENU_BUFFERS 2
/* Shader objects */
extern const u8 vpshader_basic_vpo_end[];
extern const u8 vpshader_basic_vpo[];
extern const u32 vpshader_basic_vpo_size;
extern const u8 fpshader_basic_fpo_end[];
extern const u8 fpshader_basic_fpo[];
extern const u32 fpshader_basic_fpo_size;
typedef struct
{
float x, y;
float w, h;
float min, max;
float scale[4];
float offset[4];
} rsx_viewport_t;
typedef struct
{
float x, y, z;
float nx, ny, nz;
float u, v;
float r, g, b, a;
} rsx_vertex_t;
typedef struct
{
gcmTexture tex;
u32 *data;
u32 offset;
u32 wrap_s;
u32 wrap_t;
u32 min_filter;
u32 mag_filter;
u32 width;
u32 height;
} rsx_texture_t;
typedef struct
{
int height;
int width;
int id;
uint32_t *ptr;
/* Internal stuff */
uint32_t offset;
} rsxBuffer;
typedef struct {
video_viewport_t vp;
rsxBuffer buffers[MAX_BUFFERS];
#if defined(HAVE_MENU_BUFFER)
rsxBuffer menuBuffers[MAX_MENU_BUFFERS];
int menuBuffer;
#endif
int currentBuffer, nextBuffer;
gcmContextData* context;
u16 width;
u16 height;
u16 menu_width;
u16 menu_height;
bool menu_frame_enable;
bool rgb32;
bool vsync;
u32 depth_pitch;
u32 depth_offset;
u32* depth_buffer;
#if defined(HAVE_MENU_BUFFER)
gcmSurface surface[MAX_BUFFERS+MAX_MENU_BUFFERS];
#else
gcmSurface surface[MAX_BUFFERS];
#endif
rsx_texture_t texture;
rsx_texture_t menu_texture;
rsx_vertex_t *vertices;
u32 pos_offset;
u32 uv_offset;
u32 col_offset;
rsxProgramConst *proj_matrix;
rsxProgramAttrib* pos_index;
rsxProgramAttrib* col_index;
rsxProgramAttrib* uv_index;
rsxProgramAttrib* tex_unit;
void *vp_ucode;
void *fp_ucode;
rsxVertexProgram *vpo;
rsxFragmentProgram *fpo;
u32 *fp_buffer;
u32 fp_offset;
math_matrix_4x4 mvp, mvp_no_rot;
float menu_texture_alpha;
bool smooth;
unsigned rotation;
bool keep_aspect;
bool should_resize;
bool msg_rendering_enabled;
const shader_backend_t* shader;
void* shader_data;
void* renderchain_data;
void* ctx_data;
const gfx_ctx_driver_t* ctx_driver;
bool shared_context_use;
video_info_t video_info;
struct video_tex_info tex_info; /* unsigned int alignment */
struct video_tex_info prev_info[GFX_MAX_TEXTURES]; /* unsigned alignment */
struct video_fbo_rect fbo_rect[GFX_MAX_SHADERS]; /* unsigned alignment */
} rsx_t;
#endif
+76
View File
@@ -0,0 +1,76 @@
#ifndef RA_WAYLAND_MODULE
#define RA_WAYLAND_MODULE(modname)
#endif
#ifndef RA_WAYLAND_SYM
#define RA_WAYLAND_SYM(rc,fn,params)
#endif
#ifndef RA_WAYLAND_INTERFACE
#define RA_WAYLAND_INTERFACE(iface)
#endif
#include <stdbool.h>
#ifdef HAVE_LIBDECOR_H
RA_WAYLAND_MODULE(WAYLAND_LIBDECOR)
RA_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *))
RA_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *, struct libdecor_interface *))
RA_WAYLAND_SYM(int, libdecor_dispatch, (struct libdecor *, int timeout))
RA_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\
struct wl_surface *,\
struct libdecor_frame_interface *,\
void *))
RA_WAYLAND_SYM(void, libdecor_frame_unref, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_title, (struct libdecor_frame *, const char *))
RA_WAYLAND_SYM(void, libdecor_frame_set_app_id, (struct libdecor_frame *, const char *))
RA_WAYLAND_SYM(void, libdecor_frame_set_max_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
RA_WAYLAND_SYM(void, libdecor_frame_set_min_content_size, (struct libdecor_frame *frame,\
int content_width,\
int content_height))
RA_WAYLAND_SYM(void, libdecor_frame_resize, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t,\
enum libdecor_resize_edge))
RA_WAYLAND_SYM(void, libdecor_frame_move, (struct libdecor_frame *,\
struct wl_seat *,\
uint32_t))
RA_WAYLAND_SYM(void, libdecor_frame_commit, (struct libdecor_frame *,\
struct libdecor_state *,\
struct libdecor_configuration *))
RA_WAYLAND_SYM(void, libdecor_frame_set_minimized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_maximized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_unset_maximized, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_fullscreen, (struct libdecor_frame *, struct wl_output *))
RA_WAYLAND_SYM(void, libdecor_frame_unset_fullscreen, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(void, libdecor_frame_unset_capabilities, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(bool, libdecor_frame_has_capability, (struct libdecor_frame *, \
enum libdecor_capabilities))
RA_WAYLAND_SYM(void, libdecor_frame_set_visibility, (struct libdecor_frame *, bool))
RA_WAYLAND_SYM(bool, libdecor_frame_is_visible, (struct libdecor_frame *))
RA_WAYLAND_SYM(bool, libdecor_frame_is_floating, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_set_parent, (struct libdecor_frame *,\
struct libdecor_frame *))
RA_WAYLAND_SYM(struct xdg_surface *, libdecor_frame_get_xdg_surface, (struct libdecor_frame *))
RA_WAYLAND_SYM(struct xdg_toplevel *, libdecor_frame_get_xdg_toplevel, (struct libdecor_frame *))
RA_WAYLAND_SYM(void, libdecor_frame_map, (struct libdecor_frame *))
RA_WAYLAND_SYM(struct libdecor_state *, libdecor_state_new, (int, int))
RA_WAYLAND_SYM(void, libdecor_state_free, (struct libdecor_state *))
RA_WAYLAND_SYM(bool, libdecor_configuration_get_content_size, (struct libdecor_configuration *,\
struct libdecor_frame *,\
int *,\
int *))
RA_WAYLAND_SYM(bool, libdecor_configuration_get_window_state, (struct libdecor_configuration *,\
enum libdecor_window_state *))
#endif
#undef RA_WAYLAND_MODULE
#undef RA_WAYLAND_SYM
#undef RA_WAYLAND_INTERFACE
+782
View File
@@ -0,0 +1,782 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2011-2020 - Daniel De Matteis
*
* RetroArch 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 Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <poll.h>
#include <unistd.h>
#include "wayland_common.h"
#include "../../frontend/frontend_driver.h"
#define SPLASH_SHM_NAME "retroarch-wayland-vk-splash"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
#define DEFAULT_WINDOWED_WIDTH 640
#define DEFAULT_WINDOWED_HEIGHT 480
void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl,
void *toplevel,
int32_t width, int32_t height, struct wl_array *states)
{
const uint32_t *state;
wl->fullscreen = false;
wl->maximized = false;
WL_ARRAY_FOR_EACH(state, states, const uint32_t*)
{
switch (*state)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
wl->fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
wl->maximized = true;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
wl->resize = true;
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
wl->activated = true;
break;
}
}
wl->width = width > 0 ? width : DEFAULT_WINDOWED_WIDTH;
wl->height = height > 0 ? height : DEFAULT_WINDOWED_HEIGHT;
}
void xdg_toplevel_handle_close(void *data,
struct xdg_toplevel *xdg_toplevel)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
command_event(CMD_EVENT_QUIT, NULL);
}
#ifdef HAVE_LIBDECOR_H
void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
struct libdecor_configuration *configuration,
gfx_ctx_wayland_data_t *wl)
{
int width, height;
struct libdecor_state *state = NULL;
static const enum
libdecor_window_state tiled_states = (
LIBDECOR_WINDOW_STATE_TILED_LEFT
| LIBDECOR_WINDOW_STATE_TILED_RIGHT
| LIBDECOR_WINDOW_STATE_TILED_TOP
| LIBDECOR_WINDOW_STATE_TILED_BOTTOM
);
enum libdecor_window_state window_state;
bool focused = false;
bool tiled = false;
wl->fullscreen = false;
wl->maximized = false;
if (wl->libdecor_configuration_get_window_state(
configuration, &window_state))
{
wl->fullscreen = (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
wl->maximized = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
focused = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
tiled = (window_state & tiled_states) != 0;
}
if (!wl->libdecor_configuration_get_content_size(configuration, frame,
&width, &height))
{
width = wl->floating_width;
height = wl->floating_height;
}
if ( width > 0
&& height > 0)
{
wl->width = width;
wl->height = height;
}
state = wl->libdecor_state_new(wl->width, wl->height);
wl->libdecor_frame_commit(frame, state, configuration);
wl->libdecor_state_free(state);
if (wl->libdecor_frame_is_floating(frame)) {
wl->floating_width = width;
wl->floating_height = height;
}
}
void libdecor_frame_handle_close(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
command_event(CMD_EVENT_QUIT, NULL);
}
void libdecor_frame_handle_commit(struct libdecor_frame *frame,
void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
}
#endif
void gfx_ctx_wl_get_video_size_common(gfx_ctx_wayland_data_t *wl,
unsigned *width, unsigned *height)
{
if (!wl->reported_display_size) {
wl->reported_display_size = true;
output_info_t *oi, *tmp;
oi = wl->current_output;
// If window is not ready get any monitor
if (!oi)
wl_list_for_each_safe(oi, tmp, &wl->all_outputs, link)
break;
*width = oi->width;
*height = oi->height;
} else {
*width = wl->width * wl->buffer_scale;
*height = wl->height * wl->buffer_scale;
}
}
void gfx_ctx_wl_destroy_resources_common(gfx_ctx_wayland_data_t *wl)
{
if (wl->input.dpy != NULL && wl->input.fd >= 0)
close(wl->input.fd);
#ifdef HAVE_XKBCOMMON
free_xkb();
#endif
if (wl->wl_keyboard)
wl_keyboard_destroy(wl->wl_keyboard);
if (wl->wl_pointer)
wl_pointer_destroy(wl->wl_pointer);
if (wl->wl_touch)
wl_touch_destroy(wl->wl_touch);
if (wl->cursor.theme)
wl_cursor_theme_destroy(wl->cursor.theme);
if (wl->cursor.surface)
wl_surface_destroy(wl->cursor.surface);
if (wl->seat)
wl_seat_destroy(wl->seat);
if (wl->xdg_shell)
xdg_wm_base_destroy(wl->xdg_shell);
if (wl->compositor)
wl_compositor_destroy(wl->compositor);
if (wl->registry)
wl_registry_destroy(wl->registry);
if (wl->xdg_surface)
xdg_surface_destroy(wl->xdg_surface);
if (wl->surface)
wl_surface_destroy(wl->surface);
if (wl->xdg_toplevel)
xdg_toplevel_destroy(wl->xdg_toplevel);
if (wl->idle_inhibit_manager)
zwp_idle_inhibit_manager_v1_destroy(wl->idle_inhibit_manager);
if (wl->deco)
zxdg_toplevel_decoration_v1_destroy(wl->deco);
if (wl->deco_manager)
zxdg_decoration_manager_v1_destroy(wl->deco_manager);
if (wl->idle_inhibitor)
zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
if (wl->input.dpy)
{
wl_display_flush(wl->input.dpy);
wl_display_disconnect(wl->input.dpy);
}
wl->xdg_shell = NULL;
wl->compositor = NULL;
wl->registry = NULL;
wl->input.dpy = NULL;
wl->xdg_surface = NULL;
wl->surface = NULL;
wl->xdg_toplevel = NULL;
wl->width = 0;
wl->height = 0;
}
void gfx_ctx_wl_update_title_common(gfx_ctx_wayland_data_t *wl)
{
char title[128];
title[0] = '\0';
video_driver_get_window_title(title, sizeof(title));
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
if (wl && title[0])
wl->libdecor_frame_set_title(wl->libdecor_frame, title);
}
else
#endif
{
if (wl && title[0])
{
if (wl->deco)
zxdg_toplevel_decoration_v1_set_mode(wl->deco,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
xdg_toplevel_set_title(wl->xdg_toplevel, title);
}
}
}
bool gfx_ctx_wl_get_metrics_common(gfx_ctx_wayland_data_t *wl,
enum display_metric_types type, float *value)
{
output_info_t *oi, *tmp;
oi = wl->current_output;
if (!oi)
wl_list_for_each_safe(oi, tmp, &wl->all_outputs, link)
break;
switch (type)
{
case DISPLAY_METRIC_MM_WIDTH:
*value = (float)oi->physical_width;
break;
case DISPLAY_METRIC_MM_HEIGHT:
*value = (float)oi->physical_height;
break;
case DISPLAY_METRIC_DPI:
*value = (float)oi->width * 25.4f /
(float)oi->physical_width;
break;
default:
*value = 0.0f;
return false;
}
return true;
}
bool gfx_ctx_wl_init_common(void *video_driver,
const toplevel_listener_t *toplevel_listener, gfx_ctx_wayland_data_t **wwl)
{
int i;
*wwl = calloc(1, sizeof(gfx_ctx_wayland_data_t));
gfx_ctx_wayland_data_t *wl = *wwl;
if (!wl)
return false;
#ifdef HAVE_LIBDECOR_H
#ifdef HAVE_DYNAMIC
wl->libdecor = dylib_load("libdecor-0.so");
if (wl->libdecor)
{
#define RA_WAYLAND_SYM(rc,fn,params) wl->fn = (rc (*) params)dylib_proc(wl->libdecor, #fn);
#include "wayland/libdecor_sym.h"
}
#endif
#endif
wl_list_init(&wl->all_outputs);
frontend_driver_destroy_signal_handler_state();
wl->input.dpy = wl_display_connect(NULL);
wl->last_buffer_scale = 1;
wl->buffer_scale = 1;
wl->floating_width = DEFAULT_WINDOWED_WIDTH;
wl->floating_height = DEFAULT_WINDOWED_HEIGHT;
if (!wl->input.dpy)
{
RARCH_ERR("[Wayland]: Failed to connect to Wayland server.\n");
goto error;
}
frontend_driver_install_signal_handler();
wl->registry = wl_display_get_registry(wl->input.dpy);
wl_registry_add_listener(wl->registry, &registry_listener, wl);
wl_display_roundtrip(wl->input.dpy);
if (!wl->compositor)
{
RARCH_ERR("[Wayland]: Failed to create compositor.\n");
goto error;
}
if (!wl->shm)
{
RARCH_ERR("[Wayland]: Failed to create shm.\n");
goto error;
}
if (!wl->xdg_shell)
{
RARCH_ERR("[Wayland]: Failed to create shell.\n");
goto error;
}
if (!wl->idle_inhibit_manager)
{
RARCH_LOG("[Wayland]: Compositor doesn't support zwp_idle_inhibit_manager_v1 protocol\n");
}
if (!wl->deco_manager)
{
RARCH_LOG("[Wayland]: Compositor doesn't support zxdg_decoration_manager_v1 protocol\n");
}
wl->surface = wl_compositor_create_surface(wl->compositor);
wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);
wl_surface_add_listener(wl->surface, &wl_surface_listener, wl);
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
wl->libdecor_context = wl->libdecor_new(wl->input.dpy, &libdecor_interface);
if (wl->libdecor_context)
{
wl->libdecor_frame = wl->libdecor_decorate(wl->libdecor_context, wl->surface, &toplevel_listener->libdecor_frame_interface, wl);
if (!wl->libdecor_frame)
{
RARCH_ERR("[Wayland]: Failed to crate libdecor frame\n");
goto error;
}
wl->libdecor_frame_set_app_id(wl->libdecor_frame, "retroarch");
wl->libdecor_frame_set_title(wl->libdecor_frame, "RetroArch");
wl->libdecor_frame_map(wl->libdecor_frame);
}
/* Waiting for libdecor to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
while (wl->configured)
{
if (wl->libdecor_dispatch(wl->libdecor_context, 0) < 0)
{
RARCH_ERR("[Wayland]: libdecor failed to dispatch\n");
goto error;
}
}
}
else
#endif
{
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_shell, wl->surface);
xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
xdg_toplevel_add_listener(wl->xdg_toplevel, &toplevel_listener->xdg_toplevel_listener, wl);
xdg_toplevel_set_app_id(wl->xdg_toplevel, "retroarch");
xdg_toplevel_set_title(wl->xdg_toplevel, "RetroArch");
if (wl->deco_manager)
wl->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(
wl->deco_manager, wl->xdg_toplevel);
/* Waiting for xdg_toplevel to be configured before starting to draw */
wl_surface_commit(wl->surface);
wl->configured = true;
while (wl->configured)
wl_display_dispatch(wl->input.dpy);
}
wl_display_roundtrip(wl->input.dpy);
xdg_wm_base_add_listener(wl->xdg_shell, &xdg_shell_listener, NULL);
/* Bind SHM based wl_buffer to wl_surface until the vulkan surface is ready.
* This shows the window which assigns us a display (wl_output)
* which is usefull for HiDPI and auto selecting a display for fullscreen. */
if (!draw_splash_screen(wl))
RARCH_ERR("[Wayland`]: Failed to draw splash screen\n");
wl_display_roundtrip(wl->input.dpy);
wl->input.fd = wl_display_get_fd(wl->input.dpy);
wl->input.keyboard_focus = true;
wl->input.mouse.focus = true;
wl->cursor.surface = wl_compositor_create_surface(wl->compositor);
wl->cursor.theme = wl_cursor_theme_load(NULL, 16, wl->shm);
wl->cursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr");
wl->num_active_touches = 0;
for (i = 0;i < MAX_TOUCHES;i++)
{
wl->active_touch_positions[i].active = false;
wl->active_touch_positions[i].id = -1;
wl->active_touch_positions[i].x = (unsigned) 0;
wl->active_touch_positions[i].y = (unsigned) 0;
}
flush_wayland_fd(&wl->input);
return true;
error:
return false;
}
bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl,
unsigned width, unsigned height)
{
settings_t *settings = config_get_ptr();
unsigned video_monitor_index = settings->uints.video_monitor_index;
wl->width = width ? width : DEFAULT_WINDOWED_WIDTH;
wl->height = height ? height : DEFAULT_WINDOWED_HEIGHT;
wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
{
struct libdecor_state *state = wl->libdecor_state_new(width, height);
wl->libdecor_frame_commit(wl->libdecor_frame, state, NULL);
wl->libdecor_state_free(state);
}
#endif
return true;
error:
return false;
}
bool gfx_ctx_wl_set_video_mode_common_fullscreen(gfx_ctx_wayland_data_t *wl,
bool fullscreen)
{
settings_t *settings = config_get_ptr();
unsigned video_monitor_index = settings->uints.video_monitor_index;
if (fullscreen)
{
struct wl_output *output = NULL;
int output_i = 0;
output_info_t *oi, *tmp;
if (video_monitor_index <= 0 && wl->current_output != NULL)
{
oi = wl->current_output;
output = oi->output;
RARCH_LOG("[Wayland]: Auto fullscreen on display \"%s\" \"%s\"\n", oi->make, oi->model);
}
else wl_list_for_each_safe(oi, tmp, &wl->all_outputs, link)
{
if (++output_i == video_monitor_index)
{
output = oi->output;
RARCH_LOG("[Wayland]: Fullscreen on display %i \"%s\" \"%s\"\n", output_i, oi->make, oi->model);
break;
}
}
if (output == NULL)
RARCH_LOG("[Wayland] Failed to specify monitor for fullscreen, letting compositor decide\n");
#ifdef HAVE_LIBDECOR_H
if (wl->libdecor)
wl->libdecor_frame_set_fullscreen(wl->libdecor_frame, output);
else
#endif
{
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, output);
}
}
flush_wayland_fd(&wl->input);
if (fullscreen)
{
wl->cursor.visible = false;
gfx_ctx_wl_show_mouse(wl, false);
}
else
wl->cursor.visible = true;
return true;
error:
return false;
}
bool gfx_ctx_wl_suppress_screensaver(void *data, bool state)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
if (!wl->idle_inhibit_manager)
return false;
if (state == (!!wl->idle_inhibitor))
return true;
if (state)
{
RARCH_LOG("[Wayland]: Enabling idle inhibitor\n");
struct zwp_idle_inhibit_manager_v1 *mgr = wl->idle_inhibit_manager;
wl->idle_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(mgr, wl->surface);
}
else
{
RARCH_LOG("[Wayland]: Disabling the idle inhibitor\n");
zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
wl->idle_inhibitor = NULL;
}
return true;
}
float gfx_ctx_wl_get_refresh_rate(void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
if (!wl || !wl->current_output)
return false;
return (float) wl->current_output->refresh_rate / 1000.0f;
}
bool gfx_ctx_wl_has_focus(void *data)
{
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
return wl->input.keyboard_focus;
}
void gfx_ctx_wl_check_window_common(gfx_ctx_wayland_data_t *wl,
void (*get_video_size)(void*, unsigned*, unsigned*), bool *quit,
bool *resize, unsigned *width, unsigned *height)
{
/* this function works with SCALED sizes, it's used from the renderer */
unsigned new_width, new_height;
flush_wayland_fd(&wl->input);
new_width = *width * wl->last_buffer_scale;
new_height = *height * wl->last_buffer_scale;
get_video_size(wl, &new_width, &new_height);
if ( new_width != *width * wl->last_buffer_scale
|| new_height != *height * wl->last_buffer_scale)
{
*width = new_width;
*height = new_height;
*resize = true;
wl->last_buffer_scale = wl->buffer_scale;
}
*quit = (bool)frontend_driver_get_signal_handler_state();
}
static void shm_buffer_handle_release(void *data,
struct wl_buffer *wl_buffer)
{
shm_buffer_t *buffer = data;
wl_buffer_destroy(buffer->wl_buffer);
munmap(buffer->data, buffer->data_size);
free(buffer);
}
static void xdg_surface_handle_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
xdg_surface_ack_configure(surface, serial);
}
#ifdef HAVE_LIBDECOR_H
static void libdecor_handle_error(struct libdecor *context,
enum libdecor_error error, const char *message)
{
RARCH_ERR("[Wayland]: libdecor Caught error (%d): %s\n", error, message);
}
#endif
int create_shm_file(off_t size)
{
int fd;
int ret;
#ifdef HAVE_MEMFD_CREATE
fd = memfd_create(SPLASH_SHM_NAME, MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0) {
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
do {
ret = posix_fallocate(fd, 0, size);
} while (ret == EINTR);
if (ret != 0) {
close(fd);
errno = ret;
fd = -1;
}
}
if (fd < 0)
#endif
{
for (unsigned retry_count = 0; retry_count < 100; retry_count++)
{
char *name;
if (asprintf (&name, "%s-%02d", SPLASH_SHM_NAME, retry_count) < 0)
continue;
fd = shm_open(name, O_RDWR | O_CREAT, 0600);
if (fd >= 0)
{
shm_unlink(name);
free(name);
ftruncate(fd, size);
break;
}
free(name);
}
}
return fd;
}
shm_buffer_t *create_shm_buffer(gfx_ctx_wayland_data_t *wl, int width,
int height,
uint32_t format)
{
struct wl_shm_pool *pool;
int fd, size, stride, ofd;
void *data;
shm_buffer_t *buffer;
stride = width * 4;
size = stride * height;
if (size <= 0)
return NULL;
fd = create_shm_file(size);
if (fd < 0) {
RARCH_ERR("[Wayland] [SHM]: Creating a buffer file for %d B failed: %s\n",
size, strerror(errno));
return NULL;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
RARCH_ERR("[Wayland] [SHM]: mmap failed: %s\n", strerror(errno));
close(fd);
return NULL;
}
buffer = calloc(1, sizeof *buffer);
pool = wl_shm_create_pool(wl->shm, fd, size);
buffer->wl_buffer = wl_shm_pool_create_buffer(pool, 0,
width, height,
stride, format);
wl_buffer_add_listener(buffer->wl_buffer, &shm_buffer_listener, buffer);
wl_shm_pool_destroy(pool);
close(fd);
buffer->data = data;
buffer->data_size = size;
return buffer;
}
void shm_buffer_paint_checkerboard(shm_buffer_t *buffer,
int width, int height, int scale,
size_t chk, uint32_t bg, uint32_t fg)
{
uint32_t *pixels = buffer->data;
uint32_t color;
int y, x, sx, sy;
size_t off;
int stride = width * scale;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
color = (x & chk) ^ (y & chk) ? fg : bg;
for (sx = 0; sx < scale; sx++) {
for (sy = 0; sy < scale; sy++) {
off = x * scale + sx
+ (y * scale + sy) * stride;
pixels[off] = color;
}
}
}
}
}
bool draw_splash_screen(gfx_ctx_wayland_data_t *wl)
{
shm_buffer_t *buffer;
buffer = create_shm_buffer(wl,
wl->width * wl->buffer_scale,
wl->height * wl->buffer_scale,
WL_SHM_FORMAT_XRGB8888);
if (buffer == NULL)
return false;
shm_buffer_paint_checkerboard(buffer, wl->width,
wl->height, wl->buffer_scale,
16, 0xffbcbcbc, 0xff8e8e8e);
wl_surface_attach(wl->surface, buffer->wl_buffer, 0, 0);
wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);
if (wl_surface_get_version(wl->surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
wl_surface_damage_buffer(wl->surface, 0, 0,
wl->width * wl->buffer_scale,
wl->height * wl->buffer_scale);
wl_surface_commit(wl->surface);
return true;
}
const struct wl_buffer_listener shm_buffer_listener = {
shm_buffer_handle_release,
};
#ifdef HAVE_LIBDECOR_H
const struct libdecor_interface libdecor_interface = {
.error = libdecor_handle_error,
};
#endif
+102
View File
@@ -0,0 +1,102 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* RetroArch 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 Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
#include "../../input/common/wayland_common.h"
typedef struct toplevel_listener {
#ifdef HAVE_LIBDECOR_H
struct libdecor_frame_interface libdecor_frame_interface;
#endif
struct xdg_toplevel_listener xdg_toplevel_listener;
} toplevel_listener_t;
typedef struct shm_buffer {
struct wl_buffer *wl_buffer;
void *data;
size_t data_size;
} shm_buffer_t;
void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl, void *toplevel,
int32_t width, int32_t height, struct wl_array *states);
void xdg_toplevel_handle_close(void *data,
struct xdg_toplevel *xdg_toplevel);
#ifdef HAVE_LIBDECOR_H
void libdecor_frame_handle_configure_common(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, gfx_ctx_wayland_data_t *wl);
void libdecor_frame_handle_close(struct libdecor_frame *frame,
void *data);
void libdecor_frame_handle_commit(struct libdecor_frame *frame,
void *data);
#endif
void gfx_ctx_wl_get_video_size_common(gfx_ctx_wayland_data_t *wl,
unsigned *width, unsigned *height);
void gfx_ctx_wl_destroy_resources_common(gfx_ctx_wayland_data_t *wl);
void gfx_ctx_wl_update_title_common(gfx_ctx_wayland_data_t *wl);
bool gfx_ctx_wl_get_metrics_common(gfx_ctx_wayland_data_t *wl,
enum display_metric_types type, float *value);
bool gfx_ctx_wl_init_common(void *video_driver,
const toplevel_listener_t *toplevel_listener,
gfx_ctx_wayland_data_t **wl);
bool gfx_ctx_wl_set_video_mode_common_size(gfx_ctx_wayland_data_t *wl,
unsigned width, unsigned height);
bool gfx_ctx_wl_set_video_mode_common_fullscreen(gfx_ctx_wayland_data_t *wl,
bool fullscreen);
bool gfx_ctx_wl_suppress_screensaver(void *data, bool state);
bool gfx_ctx_wl_set_video_mode_common(gfx_ctx_wayland_data_t *wl,
unsigned width, unsigned height,
bool fullscreen);
float gfx_ctx_wl_get_refresh_rate(void *data);
bool gfx_ctx_wl_has_focus(void *data);
void gfx_ctx_wl_check_window_common(gfx_ctx_wayland_data_t *wl,
void (*get_video_size)(void*, unsigned*, unsigned*), bool *quit,
bool *resize, unsigned *width, unsigned *height);
int create_shm_file(off_t size);
shm_buffer_t *create_shm_buffer(gfx_ctx_wayland_data_t *wl,
int width, int height, uint32_t format);
void shm_buffer_paint_checkerboard(shm_buffer_t *buffer,
int width, int height, int scale,
size_t chk, uint32_t bg, uint32_t fg);
bool draw_splash_screen(gfx_ctx_wayland_data_t *wl);
#ifdef HAVE_LIBDECOR_H
extern const struct libdecor_interface libdecor_interface;
#endif
+8 -4
View File
@@ -1828,12 +1828,16 @@ void win32_clip_window(bool state)
{
PWINDOWINFO info;
info = (PWINDOWINFO)malloc(sizeof(*info));
info->cbSize = sizeof(PWINDOWINFO);
if (GetWindowInfo(main_window.hwnd, info))
clip_rect = info->rcClient;
if (info)
{
info->cbSize = sizeof(PWINDOWINFO);
free(info);
if (GetWindowInfo(main_window.hwnd, info))
clip_rect = info->rcClient;
free(info);
}
info = NULL;
}
else
+17 -7
View File
@@ -115,6 +115,9 @@ static void win32_display_server_destroy(void *data)
{
dispserv_win32_t *dispserv = (dispserv_win32_t*)data;
if (!dispserv)
return;
if (dispserv->orig_width > 0 && dispserv->orig_height > 0)
video_display_server_set_resolution(
dispserv->orig_width,
@@ -131,8 +134,7 @@ static void win32_display_server_destroy(void *data)
}
#endif
if (dispserv)
free(dispserv);
free(dispserv);
}
static bool win32_display_server_set_window_opacity(
@@ -170,8 +172,10 @@ static bool win32_display_server_set_window_progress(
HWND hwnd = win32_get_window();
dispserv_win32_t *serv = (dispserv_win32_t*)data;
if (serv)
serv->progress = progress;
if (!serv)
return false;
serv->progress = progress;
#ifdef HAS_TASKBAR_EXT
if (!serv->taskbar_list || !win32_taskbar_is_created())
@@ -208,8 +212,10 @@ static bool win32_display_server_set_window_decorations(void *data, bool on)
{
dispserv_win32_t *serv = (dispserv_win32_t*)data;
if (serv)
serv->decorations = on;
if (!serv)
return false;
serv->decorations = on;
/* menu_setting performs a reinit instead to properly
* apply decoration changes */
@@ -316,6 +322,8 @@ static int resolution_list_qsort_func(
if (!a || !b)
return 0;
str_a[0] = str_b[0] = '\0';
snprintf(str_a, sizeof(str_a), "%04dx%04d (%d Hz)",
a->width,
a->height,
@@ -333,7 +341,9 @@ static void *win32_display_server_get_resolution_list(
void *data, unsigned *len)
{
DEVMODE dm = {0};
unsigned i, j, count = 0;
unsigned i = 0;
unsigned j = 0;
unsigned count = 0;
unsigned curr_width = 0;
unsigned curr_height = 0;
unsigned curr_bpp = 0;
+3
View File
@@ -1033,6 +1033,7 @@ static void* ctr_init(const video_info_t* video,
void* ctrinput = NULL;
settings_t *settings = config_get_ptr();
bool lcd_bottom = settings->bools.video_3ds_lcd_bottom;
bool speedup_enable = settings->bools.new3ds_speedup_enable;
ctr_video_t* ctr = (ctr_video_t*)linearAlloc(sizeof(ctr_video_t));
if (!ctr)
@@ -1220,6 +1221,8 @@ static void* ctr_init(const video_info_t* video,
gspSetEventCallback(GSPGPU_EVENT_VBlank0,
(ThreadFunc)ctr_vsync_hook, ctr, false);
osSetSpeedupEnable(speedup_enable);
return ctr;
}
+34 -19
View File
@@ -96,10 +96,14 @@ d3d10_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w,
D3D10MapBuffer(d3d10->overlays.vbo,
D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&sprites);
sprites[index].pos.x = x;
sprites[index].pos.y = y;
sprites[index].pos.w = w;
sprites[index].pos.h = h;
if (sprites)
{
sprites[index].pos.x = x;
sprites[index].pos.y = y;
sprites[index].pos.w = w;
sprites[index].pos.h = h;
}
D3D10UnmapBuffer(d3d10->overlays.vbo);
}
@@ -132,20 +136,24 @@ static void d3d10_overlay_set_alpha(void* data, unsigned index, float mod)
D3D10MapBuffer(
d3d10->overlays.vbo,
D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&sprites);
sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF);
sprites[index].colors[1] = sprites[index].colors[0];
sprites[index].colors[2] = sprites[index].colors[0];
sprites[index].colors[3] = sprites[index].colors[0];
if (sprites)
{
sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF);
sprites[index].colors[1] = sprites[index].colors[0];
sprites[index].colors[2] = sprites[index].colors[0];
sprites[index].colors[3] = sprites[index].colors[0];
}
D3D10UnmapBuffer(d3d10->overlays.vbo);
}
static bool d3d10_overlay_load(void* data, const void* image_data, unsigned num_images)
{
D3D10_BUFFER_DESC desc;
unsigned i;
d3d10_sprite_t* sprites;
d3d10_video_t* d3d10 = (d3d10_video_t*)data;
const struct texture_image* images = (const struct texture_image*)image_data;
unsigned i = 0;
d3d10_sprite_t* sprites = NULL;
d3d10_video_t* d3d10 = (d3d10_video_t*)data;
const struct texture_image* images = (const struct texture_image*)image_data;
if (!d3d10)
return false;
@@ -268,11 +276,14 @@ static void d3d10_set_filtering(void* data, unsigned index, bool smooth, bool ct
unsigned i;
d3d10_video_t* d3d10 = (d3d10_video_t*)data;
for (i = 0; i < RARCH_WRAP_MAX; i++)
if (smooth)
{
if (smooth)
for (i = 0; i < RARCH_WRAP_MAX; i++)
d3d10->samplers[RARCH_FILTER_UNSPEC][i] = d3d10->samplers[RARCH_FILTER_LINEAR][i];
else
}
else
{
for (i = 0; i < RARCH_WRAP_MAX; i++)
d3d10->samplers[RARCH_FILTER_UNSPEC][i] = d3d10->samplers[RARCH_FILTER_NEAREST][i];
}
}
@@ -332,6 +343,9 @@ static void d3d10_free_shader_preset(d3d10_video_t* d3d10)
free(d3d10->shader_preset->pass[i].source.string.vertex);
free(d3d10->shader_preset->pass[i].source.string.fragment);
free(d3d10->pass[i].semantics.textures);
d3d10->shader_preset->pass[i].source.string.vertex = NULL;
d3d10->shader_preset->pass[i].source.string.fragment = NULL;
d3d10->pass[i].semantics.textures = NULL;
d3d10_release_shader(&d3d10->pass[i].shader);
d3d10_release_texture(&d3d10->pass[i].rt);
d3d10_release_texture(&d3d10->pass[i].feedback);
@@ -994,9 +1008,9 @@ static void *d3d10_gfx_init(const video_info_t* video,
{
D3D10_RASTERIZER_DESC desc = { (D3D10_FILL_MODE)0 };
desc.FillMode = D3D10_FILL_SOLID;
desc.CullMode = D3D10_CULL_NONE;
desc.ScissorEnable = TRUE;
desc.FillMode = D3D10_FILL_SOLID;
desc.CullMode = D3D10_CULL_NONE;
desc.ScissorEnable = TRUE;
D3D10CreateRasterizerState(d3d10->device, &desc, &d3d10->state);
}
@@ -1560,7 +1574,7 @@ static bool d3d10_gfx_frame(
#ifndef __WINRT__
win32_update_title();
#endif
DXGIPresent(d3d10->swapChain, !!d3d10->vsync, 0);
DXGIPresent(d3d10->swapChain, d3d10->swap_interval, 0);
return true;
}
@@ -1575,6 +1589,7 @@ static void d3d10_gfx_set_nonblock_state(void* data, bool toggle,
return;
d3d10->vsync = !toggle;
d3d10->swap_interval = (!toggle) ? swap_interval : 0;
}
static bool d3d10_gfx_alive(void* data)
Loaded 100 of 523 files, more files were not shown because too many files have changed in this diff. Show more